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

Índice

Primeiros passos

Do zero ao primeiro push com prova de entrega — pelo SDK React Native ou direto pela API, com os dois comandos que você copia e roda.

Primeiros passos

Ao fim desta página você vai ter um aparelho registrado, um push enviado e — a parte que distingue o PushMesh — a prova de que a mensagem chegou ao aparelho, não apenas de que o provedor aceitou entregá-la.

Guarde estas duas palavras, porque o resto da documentação as usa o tempo todo:

NúmeroO que significa
successfulo FCM/APNs aceitou a mensagem. É o que todo serviço de push sabe dizer.
recebidoso aparelho devolveu a prova de que a notificação chegou. É o que você veio buscar aqui.

Os endereços

EndereçoPara que serve
https://api.pushmesh.ioa API pública. É o endereço de tudo nesta referência: o seu servidor, o SDK e qualquer cliente próprio falam aqui
https://app.pushmesh.ioo painel — onde nasce o aplicativo, a chave e as credenciais de entrega
https://pushmesh.ioo site

Passe sempre baseUrl para o SDK. A versão publicada hoje no npm (@pushmesh/sdk@0.7.2) traz outro endereço embutido como padrão para quando baseUrl é omitido, e esse endereço não está no ar. Omitindo o campo, o aparelho não registra e você não recebe erro nenhum do servidor — a chamada nem chega a sair. Os exemplos desta página passam baseUrl explicitamente, e você deve fazer o mesmo até uma versão nova do pacote corrigir o padrão.


Antes de começar

Três coisas, e todas vêm do painel em https://app.pushmesh.io:

O quePara que serveOnde pegar
app_id (UUID)identifica o seu aplicativo em toda chamadao painel mostra no cadastro do aplicativo
Chave da API pm_live_…autentica as chamadas do seu servidoraparece uma única vez, no momento em que o aplicativo é criado
Credencial de entrega (FCM e/ou APNs)é o que permite o push sair de verdade para o aparelhopainel → configurações do aplicativo → FCM / APNs

A credencial de entrega é um passo obrigatório, e o que ela exige não é óbvio. No Android é o arquivo .json de uma conta de serviço do Firebase (a chave de servidor legada não serve); no iOS é a chave .p8 do APNs mais Key ID, Team ID, Bundle ID e a escolha do ambiente — onde mora a armadilha clássica (TestFlight é produção). Sem ela, o disparo responde 200, o recipients vem certo e nada sai. O que ter em mãos, campo a campo, está em Credenciais de entrega — vale ler antes de criar a conta.

A chave aparece uma vez. No banco fica apenas um resumo criptográfico dela; ninguém — nem o suporte — consegue mostrá-la de novo. Perdeu, rotacione (a rotação mantém a anterior válida por 24 h, então nada quebra).

Nunca embuta a chave pm_live_ no aplicativo publicado. Um APK ou IPA é um arquivo que qualquer pessoa baixa e abre. As rotas usadas pelo aparelho (registro, recibo, In-App) foram desenhadas sem credencial exatamente por isso: o app_id viaja no corpo, e o que protege é a validação do aplicativo mais um teto por endereço de origem.

Guarde os dois valores no ambiente para poder copiar e colar os comandos abaixo:

export PUSHMESH_KEY="pm_live_a1b2c3d4_coloque_aqui_os_43_caracteres_da_sua_chave"
export APP_ID="00000000-0000-0000-0000-000000000000"

1. Confirme que você está falando com a API

curl -s https://api.pushmesh.io/
{ "servico": "pushmesh", "versao": "<versão do serviço>", "git": "<commit no ar>" }

Agora confirme que a sua chave é aceita. Esta rota não precisa de nenhum parâmetro — ela devolve como o seu aplicativo está configurado para receber confirmações:

curl -s -H "Authorization: Basic $PUSHMESH_KEY" \
  https://api.pushmesh.io/api/v1/confirmacoes
{ "modo": "consulta", "fila_pendente": 0, "streams_ativos": 0 }
  • 401 → a chave está ausente, incompleta ou não é desta conta.
  • 403 → a chave é válida, mas o aplicativo está pausado.
  • 200 → pode seguir.

Repare também no cabeçalho X-Pm-Request-Id da resposta (use curl -i para vê-lo). Ele vem em toda resposta, de sucesso ou de erro, e é o identificador que o suporte pede para achar a sua chamada.


2. Registre um aparelho

Registrar é dizer ao PushMesh: “este token de push pertence a este aplicativo”. O que volta é um player_id — o identificador público do aparelho, o que você usa para mandar mensagem para ele.

Caminho A — SDK React Native (recomendado)

O pacote está publicado no npm e faz sozinho o registro, a renovação do token, o recibo de entrega e o recibo de clique.

npm install @pushmesh/sdk @notifee/react-native @react-native-async-storage/async-storage
cd ios && bundle exec pod install   # iOS
import PushMesh from '@pushmesh/sdk';

// uma vez, no boot do app
await PushMesh.init({
  appId: 'SEU_APP_ID',
  baseUrl: 'https://api.pushmesh.io',   // obrigatório na 0.7.2 — veja a nota acima
  appVersion: '1.0.0',
});

// no login do seu app, para poder disparar por identificador de usuário
await PushMesh.login('usuario-123');

// o identificador do aparelho, se você quiser mandar direto para ele
const playerId = await PushMesh.getPlayerId();

Peça a permissão — o init não pede por você

Este é o segundo passo obrigatório que costuma faltar. O SDK não solicita a permissão de notificação no init, de propósito: quem escolhe o momento de pedir é o seu aplicativo, não a biblioteca. Em Android 13 ou mais novo e em qualquer iOS, sem esse pedido o aparelho registra normalmente, o disparo responde successful: 1 — e recebidos fica em 0 para sempre.

// no momento certo do seu fluxo (nunca no primeiro segundo do app)
if (await PushMesh.permissions.canRequestNatively()) {
  // ainda dá para o pedido nativo: um toque, sem sair do app
  await PushMesh.permissions.checkAndReport();
} else {
  // já houve uma decisão antes — só os Ajustes do sistema revertem
  await PushMesh.permissions.openNotificationSettings();
}

canRequestNatively() é o “botão inteligente”: ele responde true só enquanto o sistema ainda aceita o diálogo nativo. Mandar para os Ajustes quem nunca viu o pedido é péssimo — no iOS, um aplicativo que nunca pediu permissão sequer tem página nos Ajustes, e a pessoa cai na raiz e se perde.

Honestidade sobre o notification_types: o SDK lê a permissão real do sistema e reporta a mudança ao servidor, mas nenhuma rota desta API grava hoje os estados “bloqueou” (-2) ou “nunca pediu” (0). Um aparelho registrado nasce com notification_types: 1 e assim permanece; o que muda ao longo da vida dele é o invalid_identifier. Para “consigo alcançar este aparelho?”, a pergunta verdadeira hoje é invalid_identifier === false.

O que o SDK passa a fazer sem mais nenhuma linha sua:

  • registra o aparelho e mantém o token atualizado;
  • exibe a notificação recebida;
  • manda o recibo de entrega quando o push chega e o recibo de clique quando a pessoa toca — é isso que alimenta o número recebidos;
  • guarda os recibos numa fila local quando o aparelho está sem rede, e os reenvia no próximo arranque.

Se o seu aplicativo já tem Firebase próprio, passe o token que você já obtém (init({ appId, getToken })) e o resto continua igual. Há um diagnóstico de linha de comando que confere a integração de fora:

npx pushmesh-doctor --base-url https://api.pushmesh.io --app-id "$APP_ID"

Caminho B — direto pela API

É o caminho de quem escreve o próprio cliente (outra plataforma, um aparelho embarcado, um teste). Esta rota não leva Authorization:

curl -s -X POST https://api.pushmesh.io/api/v1/players \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "'"$APP_ID"'",
    "device_type": 1,
    "identifier": "TOKEN_DE_PUSH_DO_APARELHO",
    "external_user_id": "usuario-123",
    "app_version": "1.0.0",
    "language": "pt",
    "timezone": -10800
  }'
{ "success": true, "id": "0198e7c4-77a1-7bd2-b0f1-6b1d3f2a9c40" }

Esse id é o player_id. Guarde-o.

CampoTipoObrigatórioLimiteO que faz
app_idUUIDsimo aplicativo dono do aparelho. Inexistente ⇒ 400; pausado ⇒ 403.
device_typeinteirosim0 iOS · 1 Android · 5 Chrome · 7 Safari · 8 Firefoxa plataforma. Outro valor ⇒ 400 nomeado.
identifierstringsim194 byteso token de push do aparelho. Vazio ou maior que o limite ⇒ 400.
external_user_idstringnão128 bytes; até 10 aparelhos por valoro seu identificador de pessoa — é o que permite disparar sem conhecer o token.
app_versionstringnãoversão do seu aplicativo.
device_modelstringnãomodelo do aparelho.
tagsobjeto JSONnão2 KB já serializadopares livres para segmentar. Lista ou string ⇒ 400.
languagestringnão32 bytesidioma do aparelho.
timezoneinteironão±86400fuso em segundos (-10800 = UTC−3). Nome de fuso aqui ⇒ 400.

Três comportamentos que economizam a sua primeira tarde:

  1. O sucesso é 200, não 201 — inclusive na primeira vez.
  2. Registrar de novo o mesmo token devolve o mesmo player_id. A rota é idempotente por aplicativo + token: chame a cada abertura do app, sem medo.
  3. No POST, campo omitido apaga o valor gravado para external_user_id, app_version, device_model, tags, language e timezone. Mande sempre o retrato completo do aparelho — ou faça alterações pontuais pelo PUT /api/v1/players/{id}, onde campo ausente nunca apaga nada. Os detalhes dos dois verbos estão em Aparelhos.

Ensaio sem aparelho: um identifier que começa com test: (por exemplo test:ok) registra normalmente e devolve um player_id — serve para validar a sua integração de registro. Mas ele é marcado como aparelho de ensaio e fica de fora de qualquer disparo, de propósito. Para ver o recibo de verdade na etapa 4, use um aparelho real.


3. Dispare o push

Agora sim com a chave, porque quem dispara é o seu servidor:

curl -s -X POST https://api.pushmesh.io/api/v1/notifications \
  -H "Authorization: Basic $PUSHMESH_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "'"$APP_ID"'",
    "include_player_ids": ["0198e7c4-77a1-7bd2-b0f1-6b1d3f2a9c40"],
    "headings": { "en": "Order shipped", "pt": "Pedido a caminho" },
    "contents": { "en": "It arrives tomorrow", "pt": "Chega amanhã" }
  }'
{ "id": "0198e7d1-1c40-7f2a-9b31-77aa10c4e001", "recipients": 1 }

Esse id é o disparo. Ele é também o pm_msg_id que viaja dentro do payload do push, e é por ele que o recibo do aparelho encontra o caminho de volta.

Regras mínimas do corpo:

CampoTipoObrigatórioO que faz
app_idUUIDsimprecisa ser o aplicativo da chave, senão 401.
contentsobjeto {idioma: texto}simo corpo da mensagem. Objeto vazio ⇒ 400.
headingsobjeto {idioma: texto}nãoo título.
um alvosiminclude_player_ids (até 2.000), include_external_user_ids (até 2.000) ou included_segments (até 10 nomes). Nenhum ou mais de um ⇒ 400.

Para um envio amplo, troque o alvo por um segmento:

"included_segments": ["Subscribed Users"]

Os nomes aceitos são Subscribed Users (e o sinônimo Total Subscriptions), Active Users (vistos nos últimos 7 dias) e Engaged Users (devolveram recibo nos últimos 7 dias). Nome desconhecido responde 400 listando os válidos.

Ensaie antes, se quiser. Com o cabeçalho X-Dry-Run: true a chamada resolve o público de verdade, devolve recipients real e não entrega nada, nem grava nada:

curl -s -X POST https://api.pushmesh.io/api/v1/notifications \
  -H "Authorization: Basic $PUSHMESH_KEY" \
  -H "X-Dry-Run: true" \
  -H "Content-Type: application/json" \
  -d '{"app_id":"'"$APP_ID"'","included_segments":["Subscribed Users"],"contents":{"pt":"teste"}}'
{ "id": "", "recipients": 12840, "dry_run": true }

Duas respostas 200 que parecem erro e não são

{ "id": "", "recipients": 0, "errors": ["All included players are not subscribed"] }

Ninguém do alvo estava alcançável. Não é 4xx e não adianta repetir: ou os identificadores não existem neste aplicativo, ou os aparelhos não estão inscritos, ou eram aparelhos de ensaio.

{
  "id": "0198e7d1-1c40-7f2a-9b31-77aa10c4e001",
  "recipients": 1,
  "errors": { "invalid_player_ids": ["11111111-1111-1111-1111-111111111111"] }
}

Envio parcial: os válidos foram, e a resposta diz quais ficaram de fora. Repare que aqui errors é um objeto, e no caso anterior era um array — se você desserializa para um tipo fixo, aceite a união.


4. Veja o recibo

curl -s -H "Authorization: Basic $PUSHMESH_KEY" \
  "https://api.pushmesh.io/api/v1/notifications/0198e7d1-1c40-7f2a-9b31-77aa10c4e001?app_id=$APP_ID"
{
  "id": "0198e7d1-1c40-7f2a-9b31-77aa10c4e001",
  "successful": 1,
  "failed": 0,
  "errored": 0,
  "remaining": 0,
  "converted": 0,
  "recebidos": 1,
  "queued_at": 1756300000,
  "completed_at": 1756300003,
  "contents": { "en": "It arrives tomorrow", "pt": "Chega amanhã" },
  "platform_delivery_stats": {
    "android": { "successful": 1, "failed": 0 },
    "ios": { "successful": 0, "failed": 0 }
  },
  "pm_metricas": { "via": "rest", "cobertura_recibo_pct": 100.0, "ttfd_ms": null, "duracao_ms": 3000 }
}

O exemplo acima está abreviado: a resposta traz também o título, o alvo e a janela de agendamento. A lista completa está em Recibos de entrega.

CampoO que significa
successfulo provedor aceitou. Não é prova de chegada.
failedrejeição permanente (token morto, por exemplo).
erroredas três tentativas de envio se esgotaram.
remainingainda em processamento. Tem que chegar a zero.
convertedcliques confirmados pelo aparelho. 0 quer dizer “ninguém tocou”.
recebidosquantos aparelhos provaram que receberam.
pm_metricas.cobertura_recibo_pctrecebidos ÷ successful, em porcentagem.

Duas honestidades sobre esses números:

  • A cobertura raramente chega a 100%. Aparelho desligado, sem rede ou com o aplicativo desinstalado não devolve prova nenhuma. Um número abaixo de 100% é o retrato real da sua base, não defeito da plataforma.
  • recebidos: null não é zero. No plano gratuito o campo vem null acompanhado de um bloco recebidos_gate explicando que a confirmação real de entrega é recurso do plano pago. Se o seu código faz recebidos ?? 0, o limite comercial vira “zero entregas” no seu painel.

5. Quem manda o recibo

Se você está usando o SDK, ninguém: ele já mandou. Esta seção é para quem escreve o próprio cliente.

Todo push sai com dois campos dentro de data: pm_msg_id (o disparo) e pm_rcpt (uma prova criptográfica válida só para aquele disparo naquele aparelho). Quando a notificação chega, o seu cliente ecoa os dois:

curl -s -X POST https://api.pushmesh.io/api/v1/receipts \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "'"$APP_ID"'",
    "notification_id": "PM_MSG_ID_QUE_VEIO_NO_PUSH",
    "player_id": "0198e7c4-77a1-7bd2-b0f1-6b1d3f2a9c40",
    "rcpt": "PM_RCPT_QUE_VEIO_NO_PUSH",
    "evento": "recebido"
  }'
{ "ok": true }
  • evento aceita recebido (padrão) e clique. Um clique sem recibo anterior conta as duas coisas — ninguém toca no que não chegou.
  • Reenviar o mesmo recibo responde {"ok":true,"duplicado":true}: pode descartar o item da sua fila.
  • {"ok":true,"tardio":true} quer dizer “contei, por um caminho mais lento” — também é sucesso, e não deve ser tratado como duplicado.
  • Não tente calcular o rcpt. A chave que o gera nunca sai do servidor; ecoe exatamente o que veio no push. Prova errada responde 403, sempre com o mesmo texto.

6. Se nada chegou

Percorra nesta ordem — é a ordem em que as coisas costumam falhar:

SintomaCausa provável
Nenhum aparelho registrado, e nenhum erro na sua redeo SDK está sem baseUrl e falou com o endereço padrão dele, que não está no ar. Passe baseUrl: 'https://api.pushmesh.io' no init.
recipients: 0 com id vazioo alvo não existe neste aplicativo, os aparelhos não estão inscritos, ou eram aparelhos de ensaio (test:).
recipients bom, successful: 0, remaining: 0falta a credencial de entrega (FCM/APNs) no painel, ou ela está incorreta. Veja Credenciais de entrega.
successful bom, recebidos: 0o push saiu, mas o aparelho não devolveu prova: aplicativo sem permissão de notificação, desinstalado, sem rede — ou o seu cliente próprio não está chamando a rota de recibos.
403 com “app pausado”o aplicativo está pausado na conta.
422 falando em byteso payload renderizado passou de 3.891 bytes. O limite inclui 96 bytes que o servidor injeta (pm_msg_id + pm_rcpt); a mensagem de erro diz quantos bytes encurtar.
422 falando em plano e em usuários ativosa conta está no plano gratuito e passou da franquia mensal. O envio é recusado inteiro, de propósito, e repetir não resolve — o explain traz o teto, o número atual e o preço de sair do gratuito. Veja Limites.
429você bateu num teto. Veja Autenticação e erros.
Qualquer erro que você não entendeuleia explain.causa e explain.como_corrigir no corpo, e guarde o request_id.

O que fazer em seguida

Se você quer…Vá para
entender a chave, a rotação e todos os errosAutenticação e erros
ter as credenciais de FCM e APNs em ordemCredenciais de entrega
todos os campos do disparo (agendamento, imagem, prioridade, idempotência)Enviar push
a prova de entrega por dentro, o histórico e os números por janelaRecibos de entrega
gerir a base de aparelhos e exportá-laAparelhos
ser avisado em vez de perguntarWebhooks
mensagens dentro do aplicativoMensagens In-App
migrar de outro serviço de pushMigrando de outro provedor
todos os tetos, com númerosLimites
retenção, dados pessoais e exclusãoDados, retenção e privacidade
saber o que pode mudar sem avisoVersionamento