If your integration polls GET /api/v1/tickets/{id} on a schedule to detect changes, switching to webhooks gives you faster reactions, fewer requests, and less chance of being throttled. This guide walks through the cutover.
Polling has three operational costs: latency between the change and your reaction, request volume that pressures your API rate limit, and brittleness when the AlgaPSA side returns 503s during peak load. A webhook subscription replaces all three with a single signed POST per event.
A typical polling loop looks like this:
// runs every minute via cron
for (const ticketId of WATCHED_TICKET_IDS) {
const ticket = await fetch(
`https://algapsa.com/api/v1/tickets/${ticketId}`,
{ headers: { "X-API-Key": process.env.ALGA_API_KEY! } },
).then((r) => r.json());
if (ticket.data.updated_at > lastSeen[ticketId]) {
react(ticket.data);
lastSeen[ticketId] = ticket.data.updated_at;
}
}Six tickets at one-minute granularity is 360 requests per hour per integration — and each one is an independent risk for a 5xx response or a rate-limit hit.
Replace the loop with a single webhook subscription and a stateless receiver. The receiver verifies the signature, deduplicates on X-Alga-Event-Id, and reacts.
app.post(
"/webhooks/alga",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-Alga-Signature") ?? "";
if (!verify(req.body.toString("utf8"), sig, secret)) {
return res.status(401).send("bad signature");
}
const eventId = req.header("X-Alga-Event-Id")!;
if (await alreadyProcessed(eventId)) return res.status(200).send("ok");
const envelope = JSON.parse(req.body.toString("utf8"));
if (WATCHED_TICKET_IDS.has(envelope.data.ticket_id)) {
await react(envelope.data);
await markProcessed(eventId);
}
res.status(200).send("ok");
},
);The webhook envelope's data object is a curated subset of the ticket record. Most fields you would have read from GET /tickets/{id} are already there, with the same names. The fields you should expect:
Need a field that is not in the curated set? Hit GET /api/v1/tickets/{id} on receipt — you will still make far fewer requests than continuous polling, and only when something actually changed.
X-Alga-Event-Id so duplicate events are safe. ticket.created, ticket.updated, ticket.status_changed, and ticket.assigned cover the use case.PUT /api/v1/webhooks/{id}.occurred_at in the envelope to sequence on your side if order matters.