| name | gamma-webhooks-events |
| description | Handle Gamma webhooks and events for real-time updates.
Use when implementing webhook receivers, processing events,
or building real-time Gamma integrations.
Trigger with phrases like "gamma webhooks", "gamma events",
"gamma notifications", "gamma real-time", "gamma callbacks".
|
| allowed-tools | Read, Write, Edit |
| version | 1.13.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| tags | ["saas","gamma","webhooks"] |
| compatibility | Designed for Claude Code |
Gamma Webhooks & Events
Overview
Gamma's public API (v1.0) is generation-focused and does not expose a traditional webhook system at time of writing. Instead, use the poll-based pattern (GET /v1.0/generations/{id}) to detect completion. For event-driven architectures, wrap polling in a background worker that emits application-level events when generations complete or fail.
Prerequisites
- Completed
gamma-sdk-patterns setup
- Event bus or message queue (Bull, RabbitMQ, or EventEmitter)
- Understanding of the generate-poll-retrieve pattern
Gamma Event Model (Application-Level)
Since Gamma does not push events, you create them by polling:
| Synthetic Event | Trigger Condition | Use Case |
|---|
generation.started | POST /generations returns generationId | Log, notify user |
generation.completed | Poll returns status: "completed" | Download export, update DB |
generation.failed | Poll returns status: "failed" | Alert, retry, notify user |
generation.timeout | Poll exceeds max duration | Alert, escalate |
Instructions
Step 1: Event Emitter Pattern
import { EventEmitter } from "events";
import { createGammaClient } from "./client";
export const gammaEvents = new EventEmitter();
export interface GenerationEvent {
generationId: string;
status: "started" | "completed" | "failed" | "timeout";
gammaUrl?: string;
exportUrl?: string;
creditsUsed?: number;
error?: string;
}
export async function generateWithEvents(
content: string,
options: { outputFormat?: string; exportAs?: string; themeId?: string } = {}
): Promise<GenerationEvent> {
const gamma = createGammaClient({ apiKey: process.env.GAMMA_API_KEY! });
const { generationId } = await gamma.generate({
content,
: options. ?? ,
: options.,
: options.,
});
gammaEvents.(, {
generationId,
: ,
} );
deadline = .() + ;
(.() < deadline) {
result = gamma.(generationId);
(result. === ) {
: = {
generationId,
: ,
: result.,
: result.,
: result.,
};
gammaEvents.(, event);
event;
}
(result. === ) {
: = {
generationId,
: ,
: ,
};
gammaEvents.(, event);
event;
}
( (r, ));
}
: = {
generationId,
: ,
: ,
};
gammaEvents.(, timeoutEvent);
timeoutEvent;
}
Step 2: Event Listeners
import { gammaEvents, GenerationEvent } from "./events";
gammaEvents.on("generation", (event: GenerationEvent) => {
console.log(`[Gamma] ${event.status}: ${event.generationId}`);
});
gammaEvents.on("generation", async (event: GenerationEvent) => {
if (event.status === "completed") {
if (event.exportUrl) {
const res = await fetch(event.exportUrl);
const buffer = Buffer.from(await res.arrayBuffer());
console.log(`Downloaded export: ${buffer.length} bytes`);
}
await db.generations.update({
where: { generationId: event. },
: { : , : event. },
});
}
});
gammaEvents.(, (: ) => {
(event. === || event. === ) {
();
}
});
Step 3: Background Worker with Bull Queue
import Bull from "bull";
import { createGammaClient } from "../gamma/client";
const generationQueue = new Bull("gamma-generations", process.env.REDIS_URL!);
export async function queueGeneration(content: string, options: any = {}) {
return generationQueue.add(
{ content, ...options },
{ attempts: 2, backoff: { type: "exponential", delay: 10000 } }
);
}
generationQueue.process(3, async (job) => {
const gamma = createGammaClient({ apiKey: process.env.GAMMA_API_KEY! });
const { content, outputFormat, exportAs } = job.data;
const { generationId } = await gamma.generate({
content,
outputFormat: outputFormat ?? "presentation",
exportAs,
});
deadline = .() + ;
(.() < deadline) {
job.(.(, ((.() - (deadline - )) / ) * ));
result = gamma.(generationId);
(result. === ) result;
(result. === ) ();
( (r, ));
}
();
});
generationQueue.(, {
.();
});
generationQueue.(, {
.();
});
Step 4: Webhook-Style HTTP Callback (DIY)
If you want true webhook-style push notifications for integrations:
async function notifyCallback(callbackUrl: string, event: GenerationEvent) {
await fetch(callbackUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event: `generation.${event.status}`,
data: event,
timestamp: new Date().toISOString(),
}),
});
}
const result = await generateWithEvents("My presentation content");
if (result.status === "completed") {
await notifyCallback("https://your-app.com/hooks/gamma", result);
}
Error Handling
| Issue | Cause | Solution |
|---|
| Poll timeout | Generation taking too long | Increase timeout beyond 3 min for complex content |
| Missed completion | Poll interval too large | Use 5s interval (Gamma recommendation) |
| Duplicate processing | No idempotency check | Track processed generationIds in a Set or DB |
| Export URL expired | Downloaded too late | Download immediately on completion |
Resources
Next Steps
Proceed to gamma-performance-tuning for optimization.