Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Understand and manage Gamma API rate limits effectively. Use when hitting rate limits, optimizing API usage, or implementing request queuing systems. Trigger with phrases like "gamma rate limit", "gamma quota", "gamma 429", "gamma throttle", "gamma request limits".
.claude/skills/jeremylongshore-gamma-rate-limits/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | -7% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-06 | ✗→✓ | ▲ Improved | -2% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -19% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -29% | 0% |
Understand Gamma API rate limits and implement effective strategies for high-volume usage.
| Plan | Requests/min | Presentations/day | Exports/hour | |------|-------------|-------------------|--------------| | Free | 10 | 5 | 10 | | Pro | 60 | 50 | 100 | | Team | 200 | 200 | 500 | | Enterprise | Custom | Custom | Custom |
typescriptconst response = await gamma.presentations.list(); // Rate limit headers const headers = response.headers; console.log('Limit:', headers['x-ratelimit-limit']); console.log('Remaining:', headers['x-ratelimit-remaining']); console.log('Reset:', new Date(headers['x-ratelimit-reset'] * 1000)); # 1000: 1 second in ms
typescriptasync function withBackoff<T>( fn: () => Promise<T>, options = { maxRetries: 5, baseDelay: 1000 } # 1000: 1 second in ms ): Promise<T> { for (let attempt = 0; attempt < options.maxRetries; attempt++) { try { return await fn(); } catch (err) { if (err.status !== 429 || attempt === options.maxRetries - 1) { # HTTP 429 Too Many Requests throw err; } const delay = err.retryAfter ? err.retryAfter * 1000 # 1 second in ms : options.baseDelay * Math.pow(2, attempt); console.log(`Rate limited. Retrying in ${delay}ms...`); await new Promise(r => setTimeout(r, delay)); } } throw new Error('Max retries exceeded'); } // Usage const result = await withBackoff(() => gamma.presentations.create({ title: 'My Deck', prompt: 'AI overview' }) );
typescriptclass RateLimitedQueue { private queue: Array<() => Promise<any>> = []; private processing = false; private requestsPerMinute: number; private interval: number; constructor(requestsPerMinute = 60) { this.requestsPerMinute = requestsPerMinute; this.interval = 60000 / requestsPerMinute; # 60000: 1 minute in ms } async add<T>(fn: () => Promise<T>): Promise<T> { return new Promise((resolve, reject) => { this.queue.push(async () => { try { resolve(await fn()); } catch (err) { reject(err); } }); this.process(); }); } private async process() { if (this.processing) return; this.processing = true; while (this.queue.length > 0) { const fn = this.queue.shift()!; await fn(); await new Promise(r => setTimeout(r, this.interval)); } this.processing = false; } } // Usage const queue = new RateLimitedQueue(30); // 30 req/min const results = await Promise.all([ queue.add(() => gamma.presentations.create({ ... })), queue.add(() => gamma.presentations.create({ ... })), queue.add(() => gamma.presentations.create({ ... })), ]);
typescriptasync function getRateLimitStatus() { const status = await gamma.rateLimit.status(); return { limit: status.limit, remaining: status.remaining, percentUsed: ((status.limit - status.remaining) / status.limit * 100).toFixed(1), resetAt: new Date(status.reset * 1000), # 1000: 1 second in ms resetIn: Math.ceil((status.reset * 1000 - Date.now()) / 1000), # 1 second in ms }; } // Usage const status = await getRateLimitStatus(); console.log(`Used ${status.percentUsed}% of rate limit`); console.log(`Resets in ${status.resetIn} seconds`);
| Scenario | Strategy | Implementation | |----------|----------|----------------| | Occasional 429 | Exponential backoff | withBackoff() wrapper | | Consistent 429 | Request queue | RateLimitedQueue class | | Near limit | Preemptive throttle | Check remaining before call | | Burst traffic | Token bucket | Implement token bucket algorithm |
Proceed to gamma-security-basics for security best practices.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→fail | 26,531 | 21,861 | -18% | 1 | 1 | 0% | 4,530 | 4,953 | +9% | 0 | 0 | — |
case-02 | fail→fail | 25,799 | 20,093 | -22% | 1 | 1 | 0% | 4,199 | 4,128 | -2% | 0 | 0 | — |
case-03 | fail→pass | 22,283 | 10,339 | -54% | 1 | 1 | 0% | 3,804 | 3,534 | -7% | 0 | 0 | — |
case-04 | pass→fail | 18,222 | 3,960 | -78% | 1 | 1 | 0% | 2,767 | 2,039 | -26% | 0 | 0 | — |
case-05 | fail→pass | 16,040 | 9,143 | -43% | 1 | 1 | 0% | 1,953 | 2,101 | +8% | 0 | 0 | — |
case-06 | fail→pass | 11,339 | 7,419 | -35% | 1 | 1 | 0% | 1,741 | 1,706 | -2% | 0 | 0 | — |
case-07 | fail→pass | 13,527 | 7,134 | -47% | 1 | 1 | 0% | 1,984 | 1,616 | -19% | 0 | 0 | — |
case-08 | fail→pass | 20,668 | 8,293 | -60% | 1 | 1 | 0% | 2,780 | 1,983 | -29% | 0 | 0 | — |
case-09 | fail→pass | 21,146 | 4,714 | -78% | 1 | 1 | 0% | 3,171 | 2,137 | -33% | 0 | 0 | — |
case-10 | pass→pass | 13,417 | 11,176 | -17% | 1 | 1 | 0% | 2,206 | 2,409 | +9% | 0 | 0 | — |
case-11 | pass→pass | 18,011 | 2,484 | -86% | 1 | 1 | 0% | 2,021 | 1,662 | -18% | 0 | 0 | — |
case-12 | fail→pass | 10,039 | 6,970 | -31% | 1 | 1 | 0% | 1,783 | 1,636 | -8% | 0 | 0 | — |
case-13 | fail→pass | 15,180 | 9,440 | -38% | 1 | 1 | 0% | 1,787 | 2,174 | +22% | 0 | 0 | — |
case-14 | pass→pass | 8,523 | 6,722 | -21% | 1 | 1 | 0% | 1,544 | 1,615 | +5% | 0 | 0 | — |
case-15 | pass→pass | 12,736 | 8,412 | -34% | 1 | 1 | 0% | 1,537 | 2,023 | +32% | 0 | 0 | — |
case-16 | fail→pass | 9,721 | 7,164 | -26% | 1 | 1 | 0% | 977 | 1,817 | +86% | 0 | 0 | — |
case-17 | fail→pass | 12,741 | 4,788 | -62% | 1 | 1 | 0% | 1,752 | 2,411 | +38% | 0 | 0 | — |
case-18 | pass→pass | 5,655 | 8,303 | +47% | 1 | 1 | 0% | 1,401 | 2,114 | +51% | 0 | 0 | — |
case-19 | pass→pass | 16,168 | 11,327 | -30% | 1 | 1 | 0% | 2,581 | 2,766 | +7% | 0 | 0 | — |
case-20 | fail→pass | 12,818 | 4,699 | -63% | 1 | 1 | 0% | 2,522 | 2,277 | -10% | 0 | 0 | — |
case-21 | fail→pass | 10,549 | 6,112 | -42% | 1 | 1 | 0% | 1,994 | 1,460 | -27% | 0 | 0 | — |
case-22 | pass→pass | 17,983 | 16,073 | -11% | 1 | 1 | 0% | 2,819 | 3,932 | +39% | 0 | 0 | — |
case-23 | pass→pass | 20,450 | 14,863 | -27% | 1 | 1 | 0% | 3,149 | 4,737 | +50% | 0 | 0 | — |
case-24 | pass→pass | 15,010 | 8,109 | -46% | 1 | 1 | 0% | 1,641 | 2,589 | +58% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +42 percentage points is the difference between those two pass rates over the 24 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.