PushMesh
Entrar Solicitar acesso
Abrir navegação das seções

Índice

Aplicativos e chaves

Criar um aplicativo, rotacionar a chave da API e ler os parâmetros públicos do Firebase — as rotas /api/v1/apps.

Apps e chaves

Um app é a unidade de isolamento do PushMesh: os aparelhos, os disparos, as campanhas e as credenciais de entrega pertencem a um app, e nada atravessa a fronteira entre dois. O app_id é um UUID; ele é a identidade que o seu aplicativo carrega e não muda nunca.

Cada app tem uma chave de API — é ela que autentica as chamadas do seu servidor.

Endereço base: https://api.pushmesh.io

Veja também: Autenticação e erros traz o contrato completo das credenciais e a tabela de códigos HTTP.


Antes de mais nada: quem cria o app

Duas destas três rotas — criar app e rotacionar chave — exigem a chave de plataforma, que fica com quem opera o serviço, não com o cliente.

Na prática, se você é cliente do PushMesh:

  • Criar o app: no painel, em https://app.pushmesh.io. Ao criar, a chave aparece uma única vez na tela.
  • Rotacionar a chave: também no painel, na tela do app.

A referência abaixo existe porque a API é pública e o contrato é o mesmo — e porque quem roda o PushMesh na própria infraestrutura usa exatamente estas rotas. Não invente uma chave de plataforma: sem ela, as duas primeiras rotas respondem 401.

A terceira rota (firebase_params) é diferente: ela é pública de verdade, sem credencial nenhuma, e é o SDK Android que a chama.


A chave do app

pm_live_<kid>_<segredo>      produção
pm_test_<kid>_<segredo>      sandbox
  • kid: 8 caracteres [a-z0-9]. É o índice do lookup — não é segredo.
  • segredo: 43 caracteres alfanuméricos, ~256 bits de entropia.

Como usar:

Authorization: Basic pm_live_<kid>_<segredo>

Bearer funciona igual. Um cliente HTTP que só monta Basic clássico também serve: mande Basic <base64 de "qualquer-coisa:pm_live_..."> — o que vem antes dos dois-pontos é ignorado.

A chave crua nunca é guardada. No banco fica apenas o sha256 dela. Isso tem uma consequência prática que vale repetir: se você perder a chave, ela não é recuperável — só resta rotacionar.

A resolução da chave é cacheada por 60 segundos. Uma chave revogada para de funcionar em menos de um segundo, porque a revogação limpa os caches; uma chave que expirou pelo relógio da rotação pode continuar sendo aceita por até um minuto além do vencimento.


POST /api/v1/apps — criar um app

Autenticação: chave de plataforma.

Authorization: Bearer <CHAVE_DE_PLATAFORMA>

A comparação é feita em tempo constante — tentar adivinhar a chave medindo o tempo de resposta não funciona. Toda tentativa recusada fica registrada na auditoria, sem a chave tentada: guardamos no máximo o kid, e só quando a credencial apresentada tem o formato pm_*.

curl -X POST https://api.pushmesh.io/api/v1/apps \
  -H "Authorization: Bearer CHAVE_DE_PLATAFORMA" \
  -H "Content-Type: application/json" \
  -d '{
    "nome": "Meu aplicativo",
    "rate_por_min": 60000,
    "sandbox": false
  }'

Campos

CampoTipoObrigatórioComportamento
nomestringsimespaços das pontas são removidos. Vazio (ou só espaços) ⇒ 400 nome não pode ser vazio. É rótulo de painel: não vai para o aparelho e não entra em nenhuma chave
rate_por_mininteironãoritmo máximo de entrega por minuto deste app. Ausente ⇒ 60000. Zero ou negativo ⇒ 400 rate_por_min deve ser positivo
sandboxbooleanonãotrue gera chave com prefixo pm_test_; ausente ou false gera pm_live_

O que rate_por_min significa: é o ritmo com que o serviço entrega as notificações deste app aos provedores (Google e Apple), respeitado pelo despachante. Não é um teto de requisições HTTP à API.

Resposta

201 Created

{
  "id": "0198f3c1-4a2b-7c3d-8e9f-0a1b2c3d4e5f",
  "nome": "Meu aplicativo",
  "api_key": "pm_live_a1b2c3d4_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "kid": "a1b2c3d4",
  "receipt_key": "…64 caracteres hex…",
  "rate_por_min": 60000,
  "criado_em": "2026-08-27T14:00:00+00:00"
}
  • api_key e receipt_key aparecem uma única vez, aqui. Não há rota que as devolva de novo. Guarde as duas no seu cofre antes de fechar a resposta.
  • receipt_key é o segredo que prova os recibos de entrega. Ela é guardada cifrada do nosso lado e nunca sai do servidor depois desta resposta.
  • criado_em é ISO 8601 com fuso.

Erros

StatusQuando
400corpo não é JSON válido; nome vazio; rate_por_min menor ou igual a zero
401Authorization ausente ou com chave de plataforma incorreta
503chave de plataforma não configurada na instância; cofre de segredos não configurado; banco indisponível

A ordem importa: a credencial é conferida antes do corpo. Um JSON quebrado enviado sem credencial devolve 401, não 400.


POST /api/v1/apps/{id}/rotate_key — trocar a chave

Autenticação: chave de plataforma.

curl -X POST https://api.pushmesh.io/api/v1/apps/APP_ID/rotate_key \
  -H "Authorization: Bearer CHAVE_DE_PLATAFORMA" \
  -H "Content-Type: application/json" \
  -d '{"sandbox": false}'

O corpo é opcional. sandbox: true faz a nova chave sair com prefixo pm_test_; ausente ou false, sai pm_live_. O prefixo não muda mais nada: é uma marcação para você separar ambientes.

Resposta

200 OK

{
  "id": "0198f3c1-4a2b-7c3d-8e9f-0a1b2c3d4e5f",
  "api_key": "pm_live_e5f6a7b8_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "kid": "e5f6a7b8",
  "anterior_expira_em": "2026-08-28T14:00:00+00:00"
}

A janela de 24 horas

Rotação nunca produz 401. A chave anterior não morre no instante da troca: ela recebe uma validade de 24 horas e continua sendo aceita até lá. O campo anterior_expira_em diz exatamente quando ela para de valer (null se não havia chave anterior).

O que isso significa: você troca a chave, atualiza os seus serviços com calma ao longo do dia e nenhuma chamada em voo quebra. Passadas as 24 horas, a chave velha responde 401 chave inexistente, revogada ou expirada.

Some a esse prazo o cache de resolução de 60 segundos: na virada do vencimento, uma chamada com a chave velha pode ainda passar por até um minuto.

Erros

StatusQuando
401chave de plataforma ausente ou incorreta
404não existe app com esse {id}
500falha ao gravar a nova chave
503chave de plataforma não configurada na instância; banco indisponível

Um {id} fora do formato UUID é recusado antes do handler, com 400 e corpo de um corpo que não segue o envelope de erro padrão.


GET /api/v1/apps/{id}/firebase_params — parâmetros públicos do Firebase

Autenticação: nenhuma. Esta rota é pública por desenho.

O cliente cola o google-services.json uma vez no painel e o aplicativo Android deixa de precisar do arquivo embutido: o SDK busca os valores aqui, no boot. Onde conseguir esse arquivo — e a credencial que de fato envia — está em Credenciais de entrega.

Por que pode ser pública: os cinco valores devolvidos já vão dentro de todo APK publicado. Eles identificam o projeto Firebase; eles não autorizam enviar push. Não são credencial, e por isso não são tratados como uma.

curl https://api.pushmesh.io/api/v1/apps/APP_ID/firebase_params

Resposta

200 OK, quando o app tem os parâmetros configurados:

{
  "android": {
    "project_id": "meu-projeto-firebase",
    "sender_id": "123456789012",
    "app_id": "1:123456789012:android:abcdef0123456789",
    "api_key": "AIza…",
    "package_name": "com.exemplo.meuapp"
  },
  "ios": null
}

Quando ainda não foram configurados, o mesmo 200 com "android": null.

CampoO que é
project_ido projeto Firebase
sender_ido remetente numérico do projeto
app_ido identificador do app Android no Firebase, no formato 1:<número>:android:<hash>
api_keya chave de API do Firebase presente no google-services.json
package_nameo pacote do aplicativo Android
ioscampo reservado. Sempre null nesta fase — o formato já nasce estável para o SDK não precisar mudar quando o iOS chegar

Atenção ao nome. O api_key de dentro do bloco android é a chave do Firebase, pública, do arquivo do Google. Ela não é a chave do app no PushMesh (pm_live_…). São coisas diferentes com nomes parecidos, e confundir as duas é o engano mais caro que dá para cometer aqui.

Limite

Esta rota compartilha o mesmo teto das rotas de aparelho: 120 requisições por minuto por IP de origem, janela fixa de 60 segundos. Estourou, 429 com Retry-After: 60.

Erros

StatusQuando
403app pausado
404não existe app com esse {id}
429teto por IP
503banco indisponível

Repare na diferença: aqui um app_id inexistente devolve 404. Nas rotas de aparelho, o mesmo caso devolve 400 app_id inexistente, porque lá o app_id é um campo do corpo e não o recurso da URL.


Armadilhas da primeira integração

  1. Tentar criar o app pela API sendo cliente. Criar app e rotacionar chave pedem a chave de plataforma, que fica com quem opera o serviço. Cliente cria e rotaciona no painel.
  2. Não guardar a chave na hora. api_key e receipt_key aparecem uma única vez, na resposta da criação. Não existe rota para recuperá-las: no banco só mora o hash.
  3. Confundir o api_key do Firebase com a chave do app. O primeiro é público e vem do google-services.json. O segundo começa com pm_live_ e nunca pode sair do seu servidor.
  4. Achar que rotacionar derruba a chave antiga na hora. Ela vale por mais 24 horas, de propósito, para a virada não quebrar nada em voo. Se a sua exigência for cortar o acesso imediatamente, rotacionar não é o caminho.
  5. Esperar o envelope de erro num {id} malformado. Um {id} que não é UUID é recusado pelo framework, com 400 e corpo de texto simples.
  6. Esperar 200 na criação. O sucesso é 201.
  7. Ler rate_por_min como teto de API. É ritmo de entrega por minuto, não limite de requisições HTTP.
  8. Mandar credencial errada e ler o erro do corpo. A credencial é conferida primeiro: com ela errada, você recebe 401 mesmo que o JSON também esteja quebrado.
  9. Esperar dados de iOS no firebase_params. O campo ios é reservado e hoje é sempre null.