Skip to main content
miro-rate-limits Implement Miro REST API v2 rate limiting with the credit-based system,
exponential backoff, and request queuing.
Trigger with phrases like "miro rate limit", "miro throttling",
"miro 429", "miro retry", "miro backoff", "miro credits".
Zur Installation springen Skills Marktplatz Entdecken und erkunden Sie KI-Skills, die von der Community erstellt wurden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Prompt kopierenPrompt-Details anzeigen Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill miro-rate-limitsDer Befehl bleibt in einer Zeile. Scrollen Sie horizontal, um ihn vor dem Kopieren vollständig zu prüfen.
Sie bevorzugen eine lokale Kopie? Laden Sie die Dateien herunter, die SkillsMP derzeit vorliegen.
ZIP herunterladen Herunterladen... Mehr aus diesem Repository
Verwandte Berufe SOC
Basierend auf der SOC-Berufsklassifikation
name miro-rate-limits description Implement Miro REST API v2 rate limiting with the credit-based system,
exponential backoff, and request queuing.
Trigger with phrases like "miro rate limit", "miro throttling",
"miro 429", "miro retry", "miro backoff", "miro credits".
allowed-tools Read, Write, Edit version 1.6.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","miro","rate-limits","performance"] compatibility Designed for Claude Code
Miro Rate Limits
Overview
Miro measures API usage in credits , not raw request counts. Each endpoint consumes a different number of credits based on complexity. The global limit is 100,000 credits per minute per app.
Credit System
Rate Limit Levels Each Miro REST API endpoint is assigned a rate limit level that determines its credit cost:
Level Credits per Call Example Endpoints Level 1 Lower cost GET single board, GET single item Level 2 Medium cost POST create sticky note, POST create shape, POST create connector Level 3 Higher cost Batch operations, complex queries Level 4 Highest cost Export, bulk data operations
The exact credit cost per level is subject to change. Monitor via response headers.
Rate Limit Response Headers Every Miro API response includes these headers:
Header Description Example X-RateLimit-LimitTotal credits allocated per minute 100000X-RateLimit-RemainingCredits remaining in current window 99850X-RateLimit-ResetUnix timestamp when window resets 1700000060
When rate limited, the response also includes:
Header Description Example Retry-AfterSeconds to wait before retrying 30
Exponential Backoff with Jitter interface BackoffConfig {
maxRetries : number ;
baseDelayMs : number ;
maxDelayMs : number ;
jitterMs : number ;
}
const DEFAULT_BACKOFF : BackoffConfig = {
maxRetries : 5 ,
baseDelayMs : 1000 ,
maxDelayMs : 32000 ,
jitterMs : 500 ,
};
async function withBackoff<T>(
operation : () => Promise <Response >,
config = DEFAULT_BACKOFF
): Promise <T> {
for (let attempt = 0 ; attempt <= config.maxRetries ; attempt++) {
const response = await operation ();
if (response.ok ) {
return response.json ();
}
if (response.status !== 429 && response.status < 500 ) {
const error = await response.json ().catch (() => ({}));
throw new Error (`Miro API ${response.status} : ${error.message ?? 'Request failed' } ` );
}
if (attempt === config.maxRetries ) {
throw new Error (`Miro API: Max retries (${config.maxRetries} ) exceeded` );
}
const retryAfter = response.headers .get ('Retry-After' );
let delay : number ;
if (retryAfter) {
delay = parseInt (retryAfter, 10 ) * 1000 ;
} else {
const exponential = config.baseDelayMs * Math .pow (2 , attempt);
const jitter = Math .random () * config.jitterMs ;
delay = Math .min (exponential + jitter, config.maxDelayMs );
}
console .warn (
`[Miro] ${response.status} — retry ${attempt + 1 } /${config.maxRetries} in ${delay} ms`
);
await new Promise (r => setTimeout (r, delay));
}
throw new Error ('Unreachable' );
}
const board = await withBackoff<MiroBoard >(() =>
fetch ('https://api.miro.com/v2/boards' , {
headers : { 'Authorization' : `Bearer ${token} ` },
})
);
Rate Limit Monitor class MiroRateLimitMonitor {
private remaining = 100000 ;
private resetAt = 0 ;
private windowCreditsUsed = 0 ;
updateFromResponse (response : Response ): void {
const limit = response.headers .get ('X-RateLimit-Limit' );
const remaining = response.headers .get ('X-RateLimit-Remaining' );
const reset = response.headers .get ('X-RateLimit-Reset' );
if (remaining) this .remaining = parseInt (remaining, 10 );
if (reset) this .resetAt = parseInt (reset, 10 ) * 1000 ;
if (limit) {
this .windowCreditsUsed = parseInt (limit, 10 ) - this .remaining ;
}
}
shouldThrottle (): boolean {
return this .remaining < 1000 && Date .now () < this .resetAt ;
}
getWaitMs (): number {
if (!this .shouldThrottle ()) return 0 ;
return Math .max (0 , this .resetAt - Date .now ());
}
getStatus (): { remaining : number ; usedPercent : number ; resetsIn : number } {
return {
remaining : this .remaining ,
usedPercent : Math .round ((this .windowCreditsUsed / 100000 ) * 100 ),
resetsIn : Math .max (0 , this .resetAt - Date .now ()),
};
}
}
Request Queue (p-queue) For high-throughput integrations, queue requests to stay within limits.
import PQueue from 'p-queue' ;
const monitor = new MiroRateLimitMonitor ();
const miroQueue = new PQueue ({
concurrency : 5 ,
interval : 1000 ,
intervalCap : 10 ,
timeout : 30000 ,
});
async function queuedMiroFetch (path : string , options ?: RequestInit ) {
const waitMs = monitor.getWaitMs ();
if (waitMs > 0 ) {
console .warn (`[Miro] Throttling: waiting ${waitMs} ms for rate limit reset` );
await new Promise (r => setTimeout (r, waitMs));
}
return miroQueue.add (async () => {
const response = await fetch (`https://api.miro.com${path} ` , {
...options,
headers : {
'Authorization' : `Bearer ${process.env.MIRO_ACCESS_TOKEN} ` ,
'Content-Type' : 'application/json' ,
...options?.headers ,
},
});
monitor.updateFromResponse (response);
if (!response.ok ) {
if (response.status === 429 ) {
const retryAfter = parseInt (response.headers .get ('Retry-After' ) ?? '5' , 10 );
await new Promise (r => setTimeout (r, retryAfter * 1000 ));
return queuedMiroFetch (path, options);
}
throw new Error (`Miro ${response.status} : ${await response.text()} ` );
}
return response.json ();
});
}
Batch Operations to Reduce Credit Usage
for (const id of itemIds) {
const item = await miroFetch (`/v2/boards/${boardId} /items/${id} ` );
}
const allItems = await miroFetch (`/v2/boards/${boardId} /items?limit=50` );
const wantedItems = allItems.data .filter (item => itemIds.includes (item.id ));
const stickyNotes = await miroFetch (`/v2/boards/${boardId} /items?type=sticky_note&limit=50` );
Cost Estimation function estimateCreditsPerMinute (
requestsPerMinute : number ,
avgLevel : 1 | 2 | 3 | 4
): { credits : number ; percentOfLimit : number ; safe : boolean } {
const creditCost = { 1 : 5 , 2 : 10 , 3 : 20 , 4 : 50 };
const credits = requestsPerMinute * creditCost[avgLevel];
return {
credits,
percentOfLimit : Math .round ((credits / 100000 ) * 100 ),
safe : credits < 80000 ,
};
}
Error Handling Scenario Detection Action Approaching limit X-RateLimit-Remaining < 5000Reduce request frequency Rate limited HTTP 429 Backoff using Retry-After header Sustained 429s Multiple consecutive 429s Pause all requests, wait for reset Credit spike Monitor shows >80% usage Audit for unnecessary requests
Resources
Next Steps For security configuration, see miro-security-basics.