Im Tarif bleiben
Das meiste Kontingent geht für Daten drauf, die sich nicht geändert haben. Hier steht, was jeder Tarif erlaubt, welche Aufrufe frei sind, welche Form fünf Anfragen ersetzt und wie ein Skript anhält, bevor die Grenze es für Sie tut.
Was ein Tag und ein Monat erlauben
Zwei Limits zählen Anfragen, aus der Konfiguration, die die API durchsetzt: eine Tagesgrenze je Schlüssel und ein Monatskontingent für das ganze Konto. Rate Limits behandelt die Minutenseite.
| Tarif | Anfragen / Monat (Konto) | Anfragen / Tag (je Schlüssel) | MCP-Aufrufe / Tag | Seitentiefe |
|---|---|---|---|---|
| Explorer | 200 | 50 | 20 | 5 |
| Builder | 25,000 | 5,000 | 500 | 25 |
| Studio | 150,000 | 10,000 | 2,500 | Keine Grenze |
| Enterprise | 1,000,000 | 50,000 | 10,000 | Keine Grenze |
MCP-Aufrufe sind eine Untergrenze innerhalb des Anfragelimits, nie ein Zusatzkontingent: die zuerst erreichte Grenze lehnt ab, wie die MCP-Limitseite erklärt. Mehr als 10 Seiten in 90 Sekunden werden ebenfalls abgelehnt. Durchlaufen Sie den Katalog also stetig statt parallel.
Was auf das Monatslimit zählt
Das Monatskontingent des Tarifs wird durchgesetzt, nicht nur angezeigt. Das sind die Regeln, damit ein Skript darum herum planen kann.
- Der Monat gehört dem Konto. Jeder Schlüssel darin zieht aus einem gemeinsamen Topf: ein zweiter Schlüssel verdoppelt den Tarif nicht, während die Tagesgrenze je Schlüssel bleibt.
- Nur ausgelieferte Aufrufe verbrauchen ihn. Ein Aufruf, den eine Grenze mit einem
429abgelehnt hat, nicht, und ein304ebenso wenig. Eine Wiederholungsschleife gegen eine Grenze kann also keinen Monat aufbrauchen, für den sie abgelehnt wurde. Eine bedingte Anfrage bleibt der kostenlose Weg, Ihre Kontingente zu lesen, wie Caching erklärt. - Es ist ein Kalendermonat in UTC. Er geht um Mitternacht UTC am 1. auf null zurück, und
X-Monthly-Resetnennt den Zeitpunkt. Das Abrechnungsdatum eines bezahlten Tarifs verschiebt ihn nicht. - Die zuerst erreichte Grenze lehnt den Aufruf ab. Sind beide verbraucht, nennt das
429MONTHLY_CAP_EXCEEDED, weil diese Grenze länger dauert. - Die 200 Anfragen eines Explorer-Schlüssels reichen bei seiner Tagesgrenze von 50 etwa 4 Tage, danach wird jeder Aufruf bis zum 1. abgelehnt. Das ist die Größe des Tarifs, kein Fehler. Die bezahlten Tarife sind für ein Skript, das jeden Tag läuft, und ein Wechsel nach oben hebt das Kontingent sofort an, mit demselben Schlüssel.
Die Aufrufe, die nichts kosten
Es sind zwei, und zusammen entscheiden sie meist darüber, ob ein Tarif passt.
- Ein
304 Not Modifiedzählt weder gegen Ihr Tageslimit noch gegen Ihr Monatskontingent. Vorhandenes zu revalidieren ist frei, es erneut zu laden nicht. Caching erklärt die Mechanik. - Eine Antwort aus Ihrem eigenen Cache erreicht uns gar nicht. Beachten Sie das gesendete
Cache-Control, und eine stark besuchte Seite schrumpft auf einen Aufruf pro Cache-Lebensdauer. - Auch eine Webhook-Zustellung ist keine Anfrage von Ihnen, denn wir rufen Sie an. Änderungen zu empfangen statt zu pollen kostet deshalb nichts pro Datensatz, und Den Katalog spiegeln baut darauf auf.
Mehr pro Aufruf verlangen
Dieselbe Seite, dieselben Daten, ein Viertel der Anfragen. Diese Endpunkte gibt es, weil die Schleife, die sie ersetzen, die ist, die jeder zuerst schreibt.
// Four calls, one page render.const g17 = await gunspec.firearms.get('glock-g17')const p226 = await gunspec.firearms.get('sig-sauer-p226')const m9 = await gunspec.firearms.get('beretta-92fs')const p320 = await gunspec.firearms.get('sig-sauer-p320') // One call, the same page, and the fields already lined up for a// table. Up to five ids, as one comma-separated string.const { data } = await gunspec.firearms.compare({ ids: 'glock-g17,sig-sauer-p226,beretta-92fs,sig-sauer-p320',})- Bis zu fünf Datensätze in einem Aufruf vergleichen, statt jeden einzeln zu holen. Die Felder kommen bereits ausgerichtet zurück.
- Bis zu fünfzig Namen in einem Aufruf auflösen statt einzeln, wie der Resolve-Leitfaden zeigt.
- Mit
fieldsnur anfordern, was Sie rendern, und lieberper_pageerhöhen als mehr Seiten zu holen: eine Seite mit hundert kostet eine Anfrage, fünf Seiten mit zwanzig kosten fünf. - Nehmen Sie den Endpunkt, der Ihre Frage bereits beantwortet (Varianten, ähnliche Modelle, Anbauteile), statt sie aus Liste plus Schleife zusammenzusetzen.
Wie viele Anfragen noch übrig sind (X-Daily-Remaining und X-Monthly-Remaining)
Die Tagesgrenze wird je Schlüssel gezählt und das Monatskontingent je Konto, und jede Antwort sagt, wo Sie bei beiden stehen. Ein Skript oder ein CI-Job muss also weder raten noch nachfragen. Lesen Sie es aus der Antwort, die Sie ohnehin haben.
| Header | Was er Ihnen sagt |
|---|---|
X-Daily-Limit | Anfragen, die dieser Schlüssel in seinem Tarif pro UTC-Tag stellen darf. |
X-Daily-Remaining | Anfragen, die diesem Schlüssel heute nach dieser noch bleiben: die Antwort auf den letzten Aufruf, der ausgeliefert wird, sagt 0. Richten Sie Ihr Tempo danach. |
X-Daily-Reset | Wann der Tageszähler auf null zurückgeht: die nächste Mitternacht UTC, als ISO-8601-Zeitpunkt. |
X-Monthly-Limit | Anfragen, die der Tarif pro UTC-Monat erlaubt, für das ganze Konto. |
X-Monthly-Remaining | Anfragen, die dem Konto diesen Monat nach dieser noch bleiben. Nur ausgelieferte Aufrufe verbrauchen sie. |
X-Monthly-Reset | Wann das Monatskontingent auf null zurückgeht: Mitternacht UTC am 1., als ISO-8601-Zeitpunkt. |
Retry-After | Bei einem 429 die Sekunden bis zum Reset der Grenze, die abgelehnt hat: bei der Tagesgrenze höchstens ein Tag, beim Monatskontingent bis zu 31 Tage. |
TypeScript
Reads GUNSPEC_API_KEY from the environment.
import { GunSpec } from '@buun_group/gunspec-sdk' const gunspec = new GunSpec()Die Tages-Header stehen auf jeder /v1-Antwort eines Tarifs mit Tagesgrenze, auch auf einer abgelehnten Anfrage, die monatlichen auf jeder Antwort auf einen Aufruf mit Schlüssel, ein Aufruf ohne Schlüssel trägt also keinen der drei monatlichen Header. Jeder Wert ist das, was nach dem Aufruf übrig ist, der ihn geliefert hat. Sie kommen aus einem kurzen Cache, solange Sie weit unter einer Grenze liegen, und können früh um etwa eine Minute Verkehr zu hoch stehen; nahe einer Grenze sind sie live. Sie zu lesen kostet nichts, und eine bedingte Anfrage, die mit 304 antwortet, trägt sie ebenfalls und verbraucht nichts. Der Usage-Endpunkt ist selbst eine Anfrage, die zählt: nutzen Sie ihn zum Abgleichen, nicht zum Takten.
Bei null anhalten, und beim ersten 429
Eine Ablehnung ist kein Schluckauf, den man durchwiederholt. Bis die Grenze zurückgesetzt wird, wird nichts ausgeliefert, ein Aufruf davor wird abgelehnt, und ein kostenloser Schlüssel, der weiter anfragt, wird pausiert. Ein Job, der höflich scheitert, tut fünf Dinge.
- Lesen Sie
X-Daily-RemainingundX-Monthly-Remainingaus jeder Antwort und halten Sie an, sobald eines null erreicht, statt Aufrufe zu verbrauchen, die eine Grenze ablehnen wird. - Halten Sie bei einem
429mitDAILY_CAP_EXCEEDEDoderMONTHLY_CAP_EXCEEDEDbeim ersten an. Wiederholen Sie nicht in einer Schleife:Retry-Afternennt die Sekunden bis zum Reset,error.resetsAtden Zeitpunkt, und keine kürzere Wartezeit hilft. Die SDKs warten einen Reset nur ab, wenn er höchstens 30 Sekunden entfernt ist (ihre OptionmaxRetryAfterMs): ein Aufruf, der eine Sekunde vor Mitternacht abgelehnt wird, wartet und gelingt, eine längere Wartezeit kommt sofort als Fehler bei Ihnen an. - Machen Sie nach dem Reset weiter, indem Sie die Arbeit einplanen, nicht indem Sie in einer Anfrage schlafen. Starten Sie den Job nach
X-Daily-Reseterneut, oder nachX-Monthly-Reset, wenn der Monat verbraucht ist, wie es ein Cron-Eintrag täte. - Geben Sie jeder Last einen eigenen Schlüssel. Die Tagesgrenze gilt je Schlüssel, ein außer Kontrolle geratener Job kann also nicht den Tag eines anderen verbrauchen, und der Nutzungsbericht zeigt, welcher Schlüssel es war. Der Monat gehört dem Konto, die Summe begrenzt also der Tarif, nicht die Schlüssel.
- Behalten Sie, was Sie schon gelesen haben. Eine Antwort aus Ihrem Cache kostet nichts, und eine
304-Revalidierung zählt weder gegen die Tages- noch gegen die Monatsgrenze, wie Caching erklärt.
TypeScript
Run jobs until an allowance is spent, and stop the moment it is. Returns
import { GunSpec, RateLimitError } from '@buun_group/gunspec-sdk' const gunspec = new GunSpec() // where it stopped, so a scheduler can run the rest after the reset.async function runWithinLimit(jobs, work) { for (const [index, job] of jobs.entries()) { try { const res = await work(job) const { dailyRemaining, dailyReset, monthlyRemaining, monthlyReset } = res.rateLimitEinen Batch oder CI-Job auf den Rest zuschneiden
Geben Sie einen Aufruf aus, um den Spielraum zu erfahren, und nehmen Sie dann nur, was unter das kleinere der beiden Kontingente passt. Lassen Sie einen Puffer, denn die Remaining-Werte können früh am Tag um etwa eine Minute Verkehr zu hoch stehen, und überspringen Sie sauber, statt den Build scheitern zu lassen, wenn kein Platz ist. Eine bedingte Anfrage mit gespeichertem ETag antwortet mit 304 und denselben Headern und verbraucht nichts, wie Caching erklärt.
TypeScript
One cheap call at the start tells the job how much room the key has.
const probe = await gunspec.firearms.list({ per_page: 1 })const { dailyRemaining, dailyReset, monthlyRemaining, monthlyReset } = probe.rateLimitWas mit einem Schlüssel passiert, der nach einem 429 weiter anfragt
Klar gesagt, damit es nie überrascht.
- Jeder Aufruf nach der ersten Ablehnung wird ebenfalls abgelehnt. Er zählt in die Tagessumme des Schlüssels, verbraucht aber den Monat nicht.
- Ein kostenloser Schlüssel, der trotzdem weiter anfragt, wird pausiert. Er antwortet mit
403,KEY_ON_HOLDund einemRetry-After, das nennt, wann die Pause endet, eine Wiederholung bringt eine längere Pause, und ein neuer Schlüssel umgeht das nicht. - Pausiert werden nur Schlüssel, nie das Konto. Anmeldung, Portal und Abrechnung funktionieren wie gewohnt, Sie können sich also immer anmelden und den Tarif wechseln.
- Ein bezahlter Tarif wird nie pausiert. Über seinem Monatskontingent wird er bis zum Reset abgelehnt, oder bis er auf einen größeren Tarif wechselt, was das Kontingent sofort anhebt.
- Die Pause endet zu dem Zeitpunkt in
Retry-Afteroder sofort, wenn Sie auf einen bezahlten Tarif wechseln. - Halten Sie beim ersten
429an, und nichts davon passiert. Die Fehlerseite listet jeden Grund auf,KEY_ON_HOLDeingeschlossen.
Den stärksten Schlüssel beobachten, nicht den Durchschnitt
Die Tagesgrenze gilt je Schlüssel, und die API lehnt einen Schlüssel nach dem anderen ab. Ein kontoweiter Durchschnitt verdeckt also genau den, der gleich zu scheitern beginnt. Der Usage-Endpunkt nennt unter daily und perKey die Anfragen jedes Schlüssels heute, was ihm bleibt und wann es zurückgesetzt wird, und unter currentMonth den Monat des Kontos: ausgelieferte Anfragen, was bleibt und wann er auf null zurückgeht. Dieselben Zahlen stehen in Ihrem Profil. Ihn zu lesen ist selbst eine Anfrage, die zählt: takten Sie also über die Antwort-Header und heben Sie ihn dafür auf, alle Schlüssel auf einmal zu sehen.
// What the account has spent this month and what every key has spent today,// from the same counters the limits are checked against. This call is a// request that counts, so use it to see everything at once and pace from the// response headers, not from here.const { data } = await gunspec.usage.get() // The month is one figure for the whole account, and counts served calls only.const month = data.currentMonthif (month.percentage > 80) { notify(`${month.remaining} of ${month.limit} requests left this month, back at ${month.resetsAt}`)} // The day is per key. Watch the busiest key, never the account's sum: the API// refuses one key at a time, so an average hides the key about to start failing.const daily = data.dailyconst key = daily?.busiestKeyTodayif (daily && key && key.percentage > 80) { notify(`${key.keyName} has used ${key.percentage}% of today's requests, back at ${daily.resetsAt}`)} const mcp = data.mcp?.busiestKeyTodayif (mcp && mcp.percentage > 80) { notify(`${mcp.keyName} is at ${mcp.percentage}% of today's MCP allowance`)}Optimieren oder upgraden
Beides ist legitim. Das Signal sagt, worum es tatsächlich geht.
| Was Sie sehen | Was es bedeutet |
|---|---|
| Viele Anfragen, wenige verschiedene Datensätze | Cachen. Sie fragen dieselben Zeilen innerhalb ihrer Lebensdauer erneut ab. |
| Schübe von 429 zur vollen Stunde | Zeitplan entzerren und Jitter ergänzen. Ihr Cronjob stürmt, nicht Ihr Verkehr. |
| Stetig mehr verschiedene gelesene Datensätze | Upgraden. Das ist echte Nachfrage, die kein Cache wegnimmt. |
| PLAN_REQUIRED an einem Endpunkt | Upgraden oder darauf verzichten. Ein neuer Schlüssel im selben Tarif bekommt dieselbe Antwort. |
| Tiefenlimit beim Durchlauf erreicht | Den Durchlauf in engere Scheiben filtern oder in einen Tarif ohne Seitengrenze wechseln. |
| MONTHLY_CAP_EXCEEDED vor Monatsende | Erst cachen: erneute Abfragen unveränderter Datensätze lassen sich kostenlos revalidieren. Fragt jeder Aufruf etwas Neues, ist das echter Bedarf, und ein größerer Tarif hebt das Kontingent sofort an. |
| Ein Explorer-Schlüssel ist nach wenigen Tagen ausgeschöpft | Das ist der Tarif: sein Monat sind wenige Tage seiner Tagesgrenze. Ein bezahlter Tarif ist für ein Skript, das jeden Tag läuft. |