diff --git a/backend/src/modules/webhooks/routes.ts b/backend/src/modules/webhooks/routes.ts index 542248d..4145864 100644 --- a/backend/src/modules/webhooks/routes.ts +++ b/backend/src/modules/webhooks/routes.ts @@ -108,4 +108,30 @@ export async function webhookRoutes(app: FastifyInstance) { const limit = parseInt((req.query as Record).limit || '50', 10); return repo.listEvents(id, Math.min(limit, 100)); }); + + // ── Zapier-compatible polling endpoint ───────────────────── + // GET /webhooks/zapier/poll?eventType=timer.fired + // Returns recent events for Zapier polling triggers + app.get('/webhooks/zapier/poll', async req => { + const auth = await extractAuth(req); + const q = req.query as Record; + const eventType = q.eventType; + if (!eventType || !WEBHOOK_EVENT_TYPES.includes(eventType as (typeof WEBHOOK_EVENT_TYPES)[number])) { + throw new BadRequestError(`eventType query parameter must be one of: ${WEBHOOK_EVENT_TYPES.join(', ')}`); + } + const subs = await repo.listSubscriptions(auth.sub, PRODUCT_ID); + const matching = subs.filter(s => s.events.includes(eventType as (typeof WEBHOOK_EVENT_TYPES)[number])); + if (matching.length === 0) { + return { items: [] }; + } + // Return events from all matching subscriptions + const allEvents = []; + for (const sub of matching) { + const events = await repo.listEvents(sub.id, 10); + allEvents.push(...events); + } + // Sort by creation time descending + allEvents.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); + return { items: allEvents.slice(0, 25) }; + }); }