specification: API Commons Rate Limits specificationVersion: '0.1' schema: https://raw.githubusercontent.com/api-evangelist/interface-research/main/schema/api-commons.yml#/$defs/RateLimits provider: Microsoft .NET providerId: microsoft-net created: '2026-05-04' modified: '2026-08-29' generated: '2026-08-29' method: searched source: https://learn.microsoft.com/en-us/nuget/api/rate-limits supersedes: >- The 2026-05-04 bulk-sweep scaffold that previously occupied this file. Its tiers, headers and numbers were placeholders and none of them matched what NuGet publishes; every value below is now read from Microsoft's own rate-limits reference page. description: >- Published rate limits for the NuGet.org API. Limits are per-endpoint and scoped either by client IP or by API key — there are no plan tiers, because the API has no paid tiers. Two distinct exhaustion signals exist: 429 for throttling and 403 for quota. tags: - .NET - NuGet - Rate Limiting - Quotas - Throttling headers: limit: null remaining: null reset: null retryAfter: null policy: null headers_note: >- The most important finding in this artifact. NuGet publishes NO rate-limit response headers — no RateLimit-*, no X-RateLimit-*, and no Retry-After. The wait time is embedded as prose inside the JSON error body ("Rate limit is exceeded. Try again in 56 seconds."), so a client must regex a number out of a human sentence to back off correctly. An agent cannot read this limit from the response the way it reads a header, and cannot see how close it is to the limit before it hits it. responseCodes: throttled: 429 quotaExceeded: 403 serviceUnavailable: null errorBodies: throttled: '{"statusCode": 429, "message": "Rate limit is exceeded. Try again in 56 seconds."}' quotaExceeded: '{"statusCode": 403, "message": "Quota exceeded."}' limit_count: 7 limits: - name: V3 search endpoint: https://azuresearch-usnc.nuget.org/query scope: none limit: null note: >- Recorded verbatim from the docs: "We recommend using NuGet.org's V3 search APIs as it is not rate limited currently." Not limited is the published state; "currently" is Microsoft's own hedge and is preserved here rather than read as a guarantee. - name: V1 OData package metadata endpoint: GET /api/v1/Packages scope: ip limit: 1000 timeFrame: minute use_case: Query NuGet package metadata via v1 OData Packages collection - name: V1 search endpoint: GET /api/v1/Search() scope: ip limit: 3000 timeFrame: minute use_case: Search for NuGet packages via v1 Search endpoint - name: V2 OData package metadata endpoint: GET /api/v2/Packages scope: ip limit: 20000 timeFrame: minute use_case: Query NuGet package metadata via v2 OData Packages collection - name: V2 OData package count endpoint: GET /api/v2/Packages/$count scope: ip limit: 100 timeFrame: minute use_case: Query NuGet package count via v2 OData Packages collection - name: Package push endpoint: PUT /api/v2/package scope: api-key limit: 350 timeFrame: hour use_case: Upload a new NuGet package (version) via v2 push endpoint - name: Package unlist endpoint: DELETE /api/v2/package/{id}/{version} scope: api-key limit: 250 timeFrame: hour use_case: Unlist a NuGet package (version) via v2 endpoint - name: Package details web page endpoint: GET /package/{id}/{version} scope: ip limit: 50 timeFrame: minute use_case: Display package (version) details page note: >- A web-page limit, not an API limit — recorded because the docs list it and because scraping the gallery pages is the failure mode it exists to stop. Use the V3 API instead. docs_last_updated: '2020-05-11' docs_note: >- Microsoft's rate-limit page carries a "Last updated on 2020-05-11" stamp. The numbers above are what is published today, but they have not been revised in six years, which is worth knowing before designing a client around them.