Quickstart
Create a Happa plugin draft, stand up your own webhook server, verify signed requests, and receive your first test.ping in under 10 minutes.
Before you start: the Developer Portal does not host your plugin code. You will run your own backend locally or in the cloud, and Happa will send it signed webhooks.
Step 1 - Register your plugin
Open the Developer Portal. The landing page takes you into the portal first, and if you are signed out, the dashboard will prompt you to continue with Google before you create a plugin record for the backend you are about to run. For your first draft, use:
- Webhook URL: a temporary tunnel URL such as
https://abc123.ngrok.app/webhooks/happa - Scopes: start with
events.readandattendees.read - Pricing:
freewhile you test
Save the draft and copy the generated webhookSecret. You will use it in your own backend in the next step.
If sign-in does not open: check that developers.happa.site is allowed in Firebase Authentication authorized domains and that your deployed portal uses that same domain as its Firebase auth domain.
Building a payment or finance plugin? Stop here and read Financial Plugins first. Those integrations use a stricter company-review flow and are not handled like ordinary self-serve plugins.
Step 2 - Install dependencies
mkdir happa-plugin-demo
cd happa-plugin-demo
npm init -y
npm install express
Step 3 - Create your webhook server
This example verifies the HMAC signature before parsing JSON and responds quickly so Happa does not time out the delivery.
const express = require("express");
const crypto = require("crypto");
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) {
throw new Error("WEBHOOK_SECRET is required");
}
app.get("/health", (_req, res) => {
res.json({ ok: true });
});
app.use("/webhooks/happa", express.raw({ type: "application/json" }));
function verifySignature(rawBody, signatureHeader, secret) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
try {
return crypto.timingSafeEqual(
Buffer.from(signatureHeader || "", "utf8"),
Buffer.from(expected, "utf8")
);
} catch {
return false;
}
}
app.post("/webhooks/happa", (req, res) => {
const signature = req.headers["x-happa-signature"];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Invalid signature" });
}
const payload = JSON.parse(req.body.toString("utf8"));
console.log("Received", payload.type, payload.data);
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log("Listening on http://localhost:3000");
});
Step 4 - Run it behind a tunnel
WEBHOOK_SECRET=whsec_your_secret node index.js
# ngrok
ngrok http 3000
# or cloudflared
cloudflared tunnel --url http://localhost:3000
Update your plugin draft so the webhook URL points to the public tunnel endpoint plus /webhooks/happa.
Step 5 - Send a test webhook
In the plugin detail screen, click Test Webhook. Your server should log something like this:
Received test.ping {
message: "This is a test webhook from Happa. Your plugin is connected correctly.",
pluginId: "plg_123"
}
You're connected. At this point your endpoint is verifying signatures correctly and can receive real deliveries.
Step 6 - Store installation tokens for API access
Webhook deliveries do not include the installation API token. That token is created when a user installs your plugin, and your own onboarding flow should send it to your backend for storage.
// Example endpoint in your own backend
app.post("/happa/install", express.json(), async (req, res) => {
const { installationId, userId, apiToken, grantedScopes } = req.body;
await saveInstallation({
installationId,
userId,
apiToken,
grantedScopes
});
res.json({ stored: true });
});
Step 7 - Call the REST API
const response = await fetch(
"https://us-central1-happa-1aff4.cloudfunctions.net/pluginApi/events",
{
headers: {
Authorization: `Bearer ${apiToken}`
}
}
);
const data = await response.json();
console.log(data.events);
Next steps
- Build your production backend and deploy it to your own infrastructure before you submit the plugin for review.
- Read the Webhooks guide before you process real user traffic.
- Use the Scopes reference to request only the permissions you need.
- Check Event Types for payload shapes you can safely code against.