← Back to guidesGUIDE · WEBHOOKS

Subscribe to ticket events

Webhooks12 minIntermediate

This guide walks through creating a webhook subscribed to two ticket events, sending a signed test delivery, and verifying the X-Alga-Signature header on your receiver. By the end you have a working end-to-end loop you can plug into your own systems.

Endpoints used in this guide

GET/api/v1/webhooks/eventsList the supported event vocabulary.
POST/api/v1/webhooksCreate the webhook subscription.
POST/api/v1/webhooks/{id}/testSend a signed test delivery.
GET/api/v1/webhooks/{id}/deliveriesInspect what arrived.

Step 1: pick your event types

Start with two ticket events: ticket.created and ticket.assigned. You can subscribe to all six ticket events later — see the Webhooks reference for the full list.

curl
curl -X GET "https://algapsa.com/api/v1/webhooks/events" \
  -H "X-API-Key: $ALGA_API_KEY"

Step 2: create the webhook

Point the webhook at a URL on your own system that can receive POST requests over HTTPS. If you do not have a receiver yet, point at a service like webhook.site for the first test, then update the URL once your real receiver is ready.

curl
curl -X POST "https://algapsa.com/api/v1/webhooks" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ALGA_API_KEY" \
  -d '{
    "name": "Ticket subscriber",
    "url": "https://your-app.example.com/webhooks/alga",
    "event_types": ["ticket.created", "ticket.assigned"],
    "is_active": true,
    "verify_ssl": true
  }'

Step 3: capture the signing secret

The response body includes a one-time signing_secret. Copy it into your secret manager immediately — AlgaPSA will not show it again. If you miss it, rotate with POST /api/v1/webhooks/{id}/secret/rotate.

.env
ALGA_WEBHOOK_SECRET="kQqB...base64url..."

Step 4: handle the request on your side

Your receiver should read the raw request body before parsing JSON, verify the X-Alga-Signature header against ALGA_WEBHOOK_SECRET, and use X-Alga-Event-Id as the idempotency key. Reject anything that fails verification with a 401.

receiver.ts
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
const seen = new Set<string>(); // replace with a real store

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, process.env.ALGA_WEBHOOK_SECRET!)) {
      return res.status(401).send("bad signature");
    }
    const eventId = req.header("X-Alga-Event-Id");
    if (!eventId || seen.has(eventId)) return res.status(200).send("ok"); // dedupe
    seen.add(eventId);

    const envelope = JSON.parse(req.body.toString("utf8"));
    handle(envelope.event_type, envelope.data);
    res.status(200).send("ok");
  },
);

function verify(body: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.split("=") as [string, string]),
  );
  const t = Number(parts.t);
  if (!t || Math.abs(Math.floor(Date.now() / 1000) - t) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1 ?? "", "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

function handle(eventType: string, data: Record<string, unknown>): void {
  // your business logic here
}

Step 5: send a signed test delivery

The per-webhook test endpoint sends a signed envelope using the live secret. Use it to smoke-test your verification, idempotency, and handler code without waiting for a real ticket event.

curl
curl -X POST "https://algapsa.com/api/v1/webhooks/$WEBHOOK_ID/test" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $ALGA_API_KEY" \
  -d '{ "test_event_type": "ticket.assigned" }'

Step 6: inspect what arrived

The delivery shows up in the per-webhook history with is_test=true, a recorded response status, and the request/response bodies. Use this to confirm AlgaPSA reached you and saw your 200 OK.

curl
curl -X GET "https://algapsa.com/api/v1/webhooks/$WEBHOOK_ID/deliveries?limit=5" \
  -H "X-API-Key: $ALGA_API_KEY"

Step 7: trigger a real event

Create or assign a ticket in AlgaPSA. Within a few seconds your receiver should see a real delivery with is_test absent and an event_id you have not seen before. From here you can expand event_types to cover more of the ticket lifecycle.