Recursos
Alertas de espera
O Waity chama seu webhook quando a espera ao vivo de um lugar fica abaixo do seu limite, para que um agente não precise ficar perguntando. Todos os planos têm, inclusive o Free.
Como funciona
Crie um alerta para um lugar com um limite em minutos e um webhook https. Após cada minuto de ingestão, o Waity verifica os lugares que acabaram de receber leituras novas e envia por POST um corpo JSON assinado ao seu webhook quando a espera está no limite ou abaixo dele.
Um alerta lê a mesma resposta ao vivo que GET /v1/places/{id}, então nunca discorda da API. Ele só dispara quando now.usable é true, a unidade é minutos e now.value é no máximo under. Um valor mínimo (“mais de 60”), um número desatualizado ou pausado, um lugar fechado ou a falta de dados nunca disparam.
Criar um alerta
POST /v1/alerts com uma chave de API e um corpo JSON. A resposta é o alerta, com o id e o segredo de assinatura. O segredo é exibido uma vez: guarde-o onde seu webhook possa lê-lo.
| Campo | O que aceita |
|---|---|
place_id | Um lugar, faixa ou departamento. Um aeroporto, posto de fronteira ou campus hospitalar não tem uma espera única, então o id dele é recusado, com os ids das faixas ou departamentos. |
under | Minutos inteiros, de 1 a 600. |
webhook_url | Para onde o Waity envia o POST. Só https; veja as regras abaixo. |
repeat | false (o padrão) dispara uma vez e depois o alerta fica como fired. true dispara de novo depois que a espera sobe acima do limite mais 5 minutos, no máximo uma vez a cada 30 minutos. |
expires_at | Opcional, ISO 8601. O padrão é 24 horas a partir de agora; o máximo, 30 dias. |
curl -X POST "https://api.waity.ai/v1/alerts" \
-H "X-Api-Key: $WAITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"place_id":"pl_nvk0wkb3ps","under":30,"webhook_url":"https://example.com/waity/webhook"}'
201Resposta
{
"id": "al_3k9qx2m7t4p8w1za",
"place": {
"id": "pl_nvk0wkb3ps",
"name": "Ysleta Passenger Vehicles, Standard",
"category": "border"
},
"under": 30,
"unit": "min",
"repeat": false,
"webhook_url": "https://example.com/waity/webhook",
"status": "armed",
"created_at": "2026-10-31T19:02:11Z",
"expires_at": "2026-11-01T19:02:11Z",
Regras da URL do webhook
Para impedir que alertas cheguem a redes privadas, o Waity recusa uma URL de webhook que:
- não use https na porta padrão (443), ou tenha um nome de usuário ou senha;
- use um endereço IP em vez de um nome de host, de modo que endereços privados, de loopback, link-local e de metadados de nuvem são todos recusados;
- use localhost, um nome de um só rótulo, ou um nome privado ou reservado como .local, .internal, .lan ou .home.arpa;
- aponte para o próprio Waity.
O Waity não resolve nomes por conta própria e nunca segue um redirecionamento: uma resposta 3xx conta como entrega com falha.
Listar, ler e excluir
GET /v1/alerts retorna seus alertas, do mais recente ao mais antigo, com o status e a última entrega. As chaves de uma conta compartilham uma lista; uma chave sem conta tem a sua. GET /v1/alerts/{id} lê um, e DELETE /v1/alerts/{id} o exclui e encerra as entregas dele.
curl
curl "https://api.waity.ai/v1/alerts" \
-H "X-Api-Key: $WAITY_API_KEY"
curl -X DELETE "https://api.waity.ai/v1/alerts/al_3k9qx2m7t4p8w1za" \
-H "X-Api-Key: $WAITY_API_KEY"
| Status | O que aceita |
|---|---|
armed | Aguardando a espera ficar abaixo do limite. |
fired | Um alerta de uma só vez que já disparou. |
expired | Passou do expires_at sem disparar. |
failing | A última tentativa de entrega falhou; veja last_delivery. Novas tentativas seguem enquanto houver. |
disabled | 20 tentativas de entrega com falha seguidas. Crie um novo alerta quando seu webhook estiver funcionando. |
O webhook
Cada entrega é um POST com um corpo JSON. Leia warnings para o usuário primeiro, depois summary. now.value vale até now.usable_until; depois disso, consulte GET /v1/places/{id} de novo.
POST
{
"type": "wait.under",
"alert": {
"id": "al_3k9qx2m7t4p8w1za",
"under": 30
},
"place": {
"id": "pl_nvk0wkb3ps",
"name": "Ysleta Passenger Vehicles, Standard",
"category": "border",
"url": "https://waity.ai/places/ysleta-passenger-vehicles-standard-kb3ps"
},
"now": {
"value": 25,
"unit": "min",
"measured_at": "2026-10-31T13:58:00-06:00",
"usable_until": "2026-10-31T15:28:00-06:00",
"basis": "estimate"
},
"summary": "About 25 min to enter the US, estimated by the border agency, updated 2 min ago.",
"warnings": [],
"links": {
"place": "https://api.waity.ai/v1/places/pl_nvk0wkb3ps",
"page": "https://waity.ai/places/ysleta-passenger-vehicles-standard-kb3ps",
"alert": "https://api.waity.ai/v1/alerts/al_3k9qx2m7t4p8w1za",
"docs": "https://waity.ai/docs/alerts"
}
}
Cada requisição traz estes cabeçalhos:
Waity-Signature: t=<unix>,v1=<hex>:té o momento da assinatura, em segundos unix;v1é o HMAC-SHA256 da string formada port, um ponto e o corpo bruto, usando como chave o segredo inteiro do alerta.Waity-Alert: o id do alerta.Waity-Delivery: o id da entrega, o mesmo em cada nova tentativa, para você descartar duplicatas.
Verificar a assinatura
Verifique a assinatura sobre os bytes brutos antes de interpretar o JSON, compare em tempo constante e rejeite um t com mais de 5 minutos.
import crypto from "node:crypto";
import express from "express";
const app = express();
const secret = process.env.WAITY_ALERT_SECRET; // whsec_…
// The raw body: the signature covers the exact bytes Waity sent.
app.post("/waity/webhook", express.raw({ type: "application/json" }), (req, res) => {
const parts = Object.fromEntries(
(req.get("Waity-Signature") ?? "").split(",").map((p) => p.split("=", 2)),
);
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${req.body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
const ok =
fresh &&
typeof parts.v1 === "string" &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!ok) return res.status(400).end();
const event = JSON.parse(req.body);
// Read event.warnings first, then event.summary.
res.status(204).end();
});
app.listen(3000);
Novas tentativas
Responda com qualquer 2xx em até 10 segundos. Qualquer outra coisa é uma tentativa com falha, repetida cerca de 1, 5, 25 minutos depois. Após 20 tentativas com falha seguidas, o alerta é desativado.
Limites por plano
Cada plano permite um número de alertas ativos ao mesmo tempo. Um a mais recebe 409 alert_limit com uma mensagem que informa o limite do seu plano. Cada requisição de alertas conta como uma chamada; entregas nunca contam. Uma chave sem conta conta como Free.
| Plano | Alertas ativos |
|---|---|
| Free | 1 |
| Plus | 10 |
| Pro | 100 |
| Team | 1.000 |
Pronto-socorro e pronto atendimento
Em alertas de pronto-socorro e pronto atendimento, warnings[0] de cada entrega é a linha do 911, dita uma vez, como em toda resposta de pronto-socorro.
Relacionado
Depois diz quando uma espera deve cair, com base no histórico. Como ler uma resposta explica cada campo, e todos os campos estão na Referência da API.