Ir direto ao conteúdo principal

Guia para desenvolvedores

Integração de notificações de terceiros

Contrato atual de autenticação, solicitação, idempotência, limites, resultados e segurança.

Início rápido

No painel Web, crie um aplicativo de terceiros vinculado à empresa desejada. Copie o App ID e o App Secret e, se precisar do resultado final, configure um Callback URL opcional.

O Engine cria entradas para os usuários escolhidos pelo audience opcional (toda a empresa elegível por padrão) e só tenta o Push do sistema em dispositivos registrados elegíveis.

Endpoint e autenticação

Ambientes da API:

Cada solicitação JSON entre servidores deve incluir Authorization: Basic Base64(KEY:SECRET) por meio de HTTP Basic Authentication, em que KEY é o App ID e SECRET é o App Secret:

Endpoint: POST /openapi/v1/notifications.

bash
curl --request POST 'https://<your-engine-host>/openapi/v1/notifications' \
  --header 'Authorization: Basic <Base64(AppID:AppSecret)>' \
  --header 'Content-Type: application/json' \
  --data '{"requestId":"order-20260819-001","title":"Pedido concluído","body":"Seu pedido foi concluído.","imageUrls":["https://cdn.example.com/order/001-1.webp","https://cdn.example.com/order/001-2.webp"],"displayFields":[{"label":"Nome da loja","value":"Macarrão Xiao Han (Wangjing)"},{"value":"ORD-10086"}],"tags":["Concluído","Loja principal"]}'

Contrato da solicitação

Resumo dos campos

CampoObrigatórioTipoSignificado
requestIdSimstringIdentificador único criado pelo emissor e chave de idempotência. É aparado e não pode ficar vazio.
titleSimstringTítulo da notificação. É aparado e não pode ficar vazio.
bodySimstringCorpo da notificação. É aparado e não pode ficar vazio.
imageUrlsNãostring[]Imagens do detalhe, na ordem de exibição.
displayFieldsNãoobject[]Campos de texto adicionais do detalhe, em ordem.
tagsNãostring[]Tags de plain text exibidas somente no detalhe, em ordem.
audienceNãoobjectRestringe a usuários ou funções; omitido significa toda a empresa elegível.

Imagens: imageUrls

  • Omita, envie null ou [] quando não houver imagens; caso contrário, envie 1-9 URLs em ordem.
  • Cada URL é aparada, deve ser única e deve ser uma URL HTTPS absoluta sem usuário ou senha.
  • Cada URL aceita até 2048 caracteres Unicode. Uma URL inválida rejeita toda a solicitação.
  • O Engine guarda as URLs, mas não busca, verifica, faz proxy ou cache.

Campos de detalhe: displayFields

SubcampoObrigatórioLimiteExibição
labelNãoAparado, não vazio, até 32 Unicode caracteresNome do campo.
valueSimAparado, não vazio, até 256 Unicode caracteresValor do campo.
json
{
  "displayFields": [
    { "label": "Loja", "value": "Little Han Noodles (Wangjing)" },
    { "value": "ORD-10086" }
  ]
}
  • Omiti-lo, enviar null ou [] significa nenhuma linha extra; são permitidos até 10 objetos.
  • Sem label ou com label: null, o value ocupa uma linha inteira.
  • O conteúdo é sempre plain text; HTML, Markdown, links, dados aninhados, tipos e estilos não são aceitos.

Tags do detalhe: tags

  • Omita, envie null ou [] quando não houver tags. Caso contrário, envie no máximo 8 strings na ordem de exibição.
  • Cada tag é aparada e deve conter 1-20 caracteres Unicode. Valor vazio, não string, longo demais ou duplicado após aparar rejeita toda a solicitação com INVALID_REQUEST.
  • As tags são plain text não interativo, aparecem somente no detalhe e preservam a ordem.

Destinatários: audience

typeSeletorSignificado do ID
USERSuserIdsID do membro da empresa
ROLESrolesCompanyRole ID; membros válidos de qualquer função recebem.

Copie o ID do membro da empresa na lista de membros da empresa do Web Admin. O membro deve pertencer à empresa vinculada ao aplicativo de terceiros.

json
{
  "audience": { "type": "USERS", "userIds": ["companyMemberId"] }
}
json
{
  "audience": { "type": "ROLES", "roles": ["roleId"] }
}
  • Omita audience ou envie null para todos os usuários ativos elegíveis da empresa vinculada.
  • A lista aceita 1-100 strings originais; IDs são aparados, vazios ignorados e o conjunto é deduplicado e ordenado.
  • IDs inexistentes, inativos, excluídos ou de outra empresa são ignorados; os alvos válidos restantes recebem.
  • Um seletor válido sem alvos é aceito e termina com recipientCount=0; nunca há fallback para toda a empresa.
  • O seletor não correspondente pode ser omitido ou null. Misturas não nulas, types ou campos desconhecidos, listas ausentes ou vazias, itens não string e mais de 100 entradas retornam INVALID_REQUEST.

Limites e idempotência

  • O corpo completo aceita 256 KiB. requestId, title e body aceitam 128, 100 e 1000 caracteres Unicode.
  • Cada App ID aceita 10 solicitações por minuto e 100 por hora.
  • Repetir requestId com conteúdo normalizado equivalente retorna o resultado salvo. A ordem importa para imagens, campos e tags, não para o conjunto audience.
  • Conteúdo diferente com o mesmo requestId retorna IDEMPOTENCY_CONFLICT. O resultado final pode ser SUCCESS, PARTIAL_SUCCESS ou FAILED.

Resposta de aceitação

Uma solicitação válida retorna HTTP 202:

json
{
  "requestId": "order-20260819-001",
  "notificationId": "00000000-0000-0000-0000-000000000001",
  "status": "ACCEPTED"
}

ACCEPTED significa apenas que o Engine guardou a solicitação para envio, não que APNs/FCM ou o dispositivo exibiram a notificação.

Resultado do Callback

Com Callback URL configurado, o Engine envia o resultado final:

json
{
  "requestId": "order-20260819-001",
  "status": "PARTIAL_SUCCESS",
  "recipientCount": 8,
  "pushAcceptedCount": 1,
  "pushFailedCount": 1
}

recipientCount é o número de usuários destinatários da central de notificações. pushAcceptedCount e pushFailedCount são contagens de lotes do Push Outbox, não contagens de usuários ou dispositivos nem prova de entrega do banner do sistema.

Teste de Callback

Cada teste de Callback do painel administrativo envia uma sonda distinta:

json
{
  "requestId": "callback-test-<unique-id>",
  "status": "SUCCESS",
  "recipientCount": 1,
  "pushAcceptedCount": 1,
  "pushFailedCount": 0,
  "test": true
}

Quando test for true, valide a estrutura e responda com 2xx, mas não associe a sonda a uma solicitação de notificação nem atualize o estado de entrega do negócio. As contagens são valores fixos de teste, não destinatários nem lotes reais do Push Outbox.

O status final é SUCCESS, PARTIAL_SUCCESS ou FAILED. Responda com qualquer 2xx para confirmar.

Caso contrário, haverá novas tentativas após 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas e 24 horas. Atualmente não existe assinatura HMAC: exija HTTPS, confira o requestId dos resultados que não sejam de teste, restrinja a exposição e processe o Callback de forma idempotente.

Referência de erros

HTTPCodeSignificado
400INVALID_REQUESTContent-Type, JSON, tamanho ou validação inválidos.
401INVALID_APP_CREDENTIALSApp ID ou App Secret inválidos.
403APPLICATION_INACTIVEAplicativo ou empresa inativos.
409IDEMPOTENCY_CONFLICTrequestId reutilizado com conteúdo diferente.
429RATE_LIMITEDLimite do aplicativo excedido.
503NOTIFICATION_UNAVAILABLEServiço temporariamente indisponível.

Segurança e escopo de envio

  • App ID e App Secret são credenciais entre servidores. Nunca use navegador, aplicativo móvel, repositório público, URL ou armazenamento do cliente. Redefina o App Secret se houver exposição.
  • Os IDs de destino privados nunca são gravados nos logs do aplicativo. O seletor privado e seus IDs também não aparecem em GraphQL, Push, Callback, realtime nem navigation.
  • Sem audience, todos os usuários ativos elegíveis da empresa são incluídos; com audience, somente os alvos válidos resolvidos. Cada destinatário válido recebe uma entrada e é contado em recipientCount.
  • O Push do sistema só é tentado em dispositivos com um PushInstallation ativo que permita a categoria BUSINESS, sem garantir um banner em todos os dispositivos.
  • A lista completa de imageUrls fica só no detalhe autorizado. O Engine pode enviar a primeira URL de imageUrls ao APNs/FCM para um banner nativo. displayFields e tags não entram em Push nem Callback e são plain text não interativo; não inclua segredos, tokens de acesso, dados de pagamento nem valores sensíveis.
  • title e body devem permanecer completos e compreensíveis sem as imagens. Falhas ao baixar ou renderizar imagens não alteram o status de accepted, Callback ou Push.
  • O cliente móvel aceita no máximo 5 MiB por imagem e limita a operação completa de download a 10 segundos. Ele não segue redirecionamentos 3xx, portanto cada URL deve retornar a imagem diretamente.
  • O cliente móvel baixa cada imagem diretamente do CDN público. Use URLs sem autenticação nem cookies, mantenha-as disponíveis por pelo menos 90 dias e considere que o CDN recebe o IP, o horário da solicitação e o User-Agent do usuário.
  • Prefira URLs de objetos imutáveis quando a exibição histórica precisar permanecer estável.