# PyPI

> Read the Python Package Index from a workflow. Look a package up by name, read its metadata, licence, maintainers and supported Pythons, walk its full release history, and list the wheels and source distributions it ships with their download URLs and checksums. Check whether a dependency has a newer version than the one you pin, list its dependencies and their version ranges, and pull the known security advisories for any version. Watch PyPI's feeds for new releases and newly registered projects, verify which repository built a file from its signed provenance, and search all 900,000+ project names. No account or API key required.

App · Code Repositories · 14 actions. Web page: https://docs.lodol.com/docs/integrations/pypi

## Actions

### Check for a new release

Check whether a package has published anything newer than the version you already have. Give it the version a project pins and it says whether an upgrade exists, what the newest is, how many releases are in between and what they were. The step to put on a schedule to watch a dependency. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version you have (`current_version`, text): Optional. The version to compare against, e.g. the one pinned in a requirements file. Leave blank to just report the newest release. Versions are compared the way Python compares them, so 0.10 counts as newer than 0.9.
- Include pre-releases (`include_prereleases`, true/false): Optional. Count alphas, betas and release candidates as new releases. Off by default, which matches what pip installs. Default: `false`.

**Outputs**

- `current_version` (text): The version that was compared against. Null when none was given.
- `current_version_exists` (true/false): True when PyPI still publishes the version you named. False can mean a typo, or a release that was removed.
- `has_new_release` (true/false): True when something newer than your version exists. Branch on this to stay quiet until there is news.
- `is_up_to_date` (true/false): True when your version is the newest there is.
- `latest_release` (object): One published version of the project.
- `latest_version` (text): The newest version PyPI has.
- `name` (text): The project that was checked.
- `newer_releases` (list): The releases published since yours, oldest first, so a changelog reads in the order things happened.
- `project_url` (text): The project's page on pypi.org.
- `versions_behind` (number): How many releases have come out since yours. Null when no version was given to compare.

**Example output**

```json
{
  "current_version": "2.31.0",
  "current_version_exists": true,
  "has_new_release": true,
  "is_up_to_date": false,
  "latest_release": {
    "file_count": 2,
    "has_sdist": true,
    "has_wheel": true,
    "is_prerelease": false,
    "is_yanked": false,
    "release_url": "https://pypi.org/project/requests/2.32.3/",
    "released_at": "2024-05-29T15:37:47Z",
    "requires_python": ">=3.8",
    "total_size": "191.7 KB",
    "total_size_bytes": 196288,
    "version": "2.32.3",
    "yanked_reason": null
  },
  "latest_version": "2.32.3",
  "name": "requests",
  "newer_releases": [
    {
      "file_count": 2,
      "has_sdist": true,
      "has_wheel": true,
      "is_prerelease": false,
      "is_yanked": false,
      "release_url": "https://pypi.org/project/requests/2.32.3/",
      "released_at": "2024-05-29T15:37:47Z",
      "requires_python": ">=3.8",
      "total_size": "191.7 KB",
      "total_size_bytes": 196288,
      "version": "2.32.3",
      "yanked_reason": null
    }
  ],
  "project_url": "https://pypi.org/project/requests/",
  "versions_behind": 4
}
```

### Get a file's provenance

Find out which repository and which CI workflow built a distribution file, proved by the attestation signed when it was published rather than claimed in its metadata. The supply chain check for a dependency. Attestations are recent and opt-in, so many files have none; List distribution files says which do. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text, required): Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published.
- File (`filename`, text, required): Which distribution file to check. The list is fetched from PyPI, so it is always the files this version shipped, with the ones that have provenance marked.

**Outputs**

- `attestation_count` (number): How many attestations were returned.
- `bundle_count` (number): How many bundles they arrived in, one per signing identity.
- `filename` (text): The file that was checked.
- `has_provenance` (true/false): True when PyPI holds attestations for this file.
- `name` (text): The project it belongs to.
- `provenance_version` (number): The version of PyPI's provenance format this answer uses.
- `publishers` (list): Who signed the attestations, one entry per bundle.
- `release_url` (text): That release's page on pypi.org.
- `version` (text): The version it belongs to.

**Example output**

```json
{
  "attestation_count": 1,
  "bundle_count": 1,
  "filename": "pydantic-2.12.0-py3-none-any.whl",
  "has_provenance": true,
  "name": "pydantic",
  "provenance_version": 1,
  "publishers": [
    {
      "claims": {},
      "environment": "release",
      "kind": "GitHub",
      "repository": "pydantic/pydantic",
      "repository_url": "https://github.com/pydantic/pydantic",
      "workflow": "ci.yml"
    }
  ],
  "release_url": "https://pypi.org/project/pydantic/2.12.0/",
  "version": "2.12.0"
}
```

### Get a project

Get everything PyPI publishes about a package at its latest version: what it is, who maintains it, its licence, the Pythons it supports, how many releases it has, when the last one went out and how many security advisories it carries. The starting point for almost any workflow about a package. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.

**Outputs**

- `latest_files` (list): The distribution files that version shipped, with their download URLs and checksums.
- `latest_version` (text): The newest version PyPI serves for this project, repeated here so a workflow can reference it without reaching into the project.
- `project` (object): The project and everything PyPI publishes about it.

**Example output**

```json
{
  "latest_files": [
    {
      "file_type": "wheel",
      "filename": "requests-2.32.3-py3-none-any.whl",
      "has_provenance": false,
      "is_yanked": false,
      "md5": null,
      "provenance_url": null,
      "requires_python": ">=3.8",
      "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6",
      "size": "63.4 KB",
      "size_bytes": 64928,
      "uploaded_at": "2024-05-29T15:37:47Z",
      "url": "https://files.pythonhosted.org/packages/f9/9b/requests-2.32.3-py3-none-any.whl",
      "version": "2.32.3",
      "yanked_reason": null
    }
  ],
  "latest_version": "2.32.3",
  "project": {
    "author": "Kenneth Reitz",
    "author_email": "me@kennethreitz.org",
    "classifiers": [
      "Development Status :: 5 - Production/Stable",
      "Programming Language :: Python :: 3.12"
    ],
    "dependency_count": 6,
    "description_characters": 2894,
    "description_content_type": "text/markdown",
    "development_status": "Production/Stable",
    "documentation_url": "https://requests.readthedocs.io",
    "extras": [
      "socks",
      "use-chardet-on-py3"
    ],
    "homepage_url": "https://requests.readthedocs.io",
    "is_prerelease": false,
    "is_yanked": false,
    "issues_url": null,
    "keywords": [],
    "last_serial": 23984019,
    "latest_file_count": 2,
    "latest_release_date": "2024-05-29T15:37:47Z",
    "license": "Apache-2.0",
    "maintainer": null,
    "maintainer_email": null,
    "maintainers": [
      {
        "profile_url": "https://pypi.org/user/nateprewitt/",
        "role": "Owner",
        "username": "nateprewitt"
      }
    ],
    "name": "requests",
    "normalized_name": "requests",
    "organization": null,
    "project_url": "https://pypi.org/project/requests/",
    "project_urls": {
      "Documentation": "https://requests.readthedocs.io",
      "Source": "https://github.com/psf/requests"
    },
    "python_versions": [
      "3",
      "3.12"
    ],
    "release_count": 155,
    "release_url": "https://pypi.org/project/requests/2.32.3/",
    "requires_python": ">=3.8",
    "source_url": "https://github.com/psf/requests",
    "summary": "Python HTTP for Humans.",
    "version": "2.32.3",
    "vulnerability_count": 0,
    "yanked_reason": null
  }
}
```

### Get a project's description

Get a package's long description: the README shown on its PyPI page, in the Markdown or reStructuredText the author wrote. Kept out of Get a project because it can run to hundreds of kilobytes, and cut to a length you choose. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text): Optional. Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published. Leave blank for the latest release.
- Maximum length (`max_characters`, number): Optional. How much of the description to return, in characters. Between 1 and 200000; 20000 by default, which covers most READMEs whole. From 1 to 200000. Default: `20000`.

**Outputs**

- `content_type` (text): How it is written, e.g. text/markdown or text/x-rst. Null on older packages that did not say.
- `description` (text): The description itself, cut to the maximum length.
- `is_truncated` (true/false): True when the description was longer than the maximum length and was cut.
- `name` (text): The project the description belongs to.
- `project_url` (text): The project's page on pypi.org.
- `summary` (text): The one-line description, for a step that only needs a sentence.
- `total_characters` (number): How long the whole description is, before any cutting.
- `version` (text): The version the description was read from.

**Example output**

```json
{
  "content_type": "text/markdown",
  "description": "# Requests\n\nRequests is a simple HTTP library.",
  "is_truncated": true,
  "name": "requests",
  "project_url": "https://pypi.org/project/requests/",
  "summary": "Python HTTP for Humans.",
  "total_characters": 2894,
  "version": "2.32.3"
}
```

### Get a release

Get one specific version of a package, with the files it shipped and their download URLs and checksums. Use it to read the metadata of a version a project has pinned, rather than whatever is newest today. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text, required): Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published.

**Outputs**

- `file_count` (number): How many files it shipped.
- `files` (list): The distribution files this version shipped.
- `release` (object): The project and everything PyPI publishes about it.
- `total_size` (text): The same combined size written for people.
- `total_size_bytes` (number): Their combined size in bytes.

**Example output**

```json
{
  "file_count": 2,
  "files": [
    {
      "file_type": "wheel",
      "filename": "requests-2.32.3-py3-none-any.whl",
      "has_provenance": false,
      "is_yanked": false,
      "md5": null,
      "provenance_url": null,
      "requires_python": ">=3.8",
      "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6",
      "size": "63.4 KB",
      "size_bytes": 64928,
      "uploaded_at": "2024-05-29T15:37:47Z",
      "url": "https://files.pythonhosted.org/packages/f9/9b/requests-2.32.3-py3-none-any.whl",
      "version": "2.32.3",
      "yanked_reason": null
    }
  ],
  "release": {
    "author": "Kenneth Reitz",
    "author_email": "me@kennethreitz.org",
    "classifiers": [
      "Development Status :: 5 - Production/Stable",
      "Programming Language :: Python :: 3.12"
    ],
    "dependency_count": 6,
    "description_characters": 2894,
    "description_content_type": "text/markdown",
    "development_status": "Production/Stable",
    "documentation_url": "https://requests.readthedocs.io",
    "extras": [
      "socks",
      "use-chardet-on-py3"
    ],
    "homepage_url": "https://requests.readthedocs.io",
    "is_prerelease": false,
    "is_yanked": false,
    "issues_url": null,
    "keywords": [],
    "last_serial": 23984019,
    "latest_file_count": 2,
    "latest_release_date": "2024-05-29T15:37:47Z",
    "license": "Apache-2.0",
    "maintainer": null,
    "maintainer_email": null,
    "maintainers": [
      {
        "profile_url": "https://pypi.org/user/nateprewitt/",
        "role": "Owner",
        "username": "nateprewitt"
      }
    ],
    "name": "requests",
    "normalized_name": "requests",
    "organization": null,
    "project_url": "https://pypi.org/project/requests/",
    "project_urls": {
      "Documentation": "https://requests.readthedocs.io",
      "Source": "https://github.com/psf/requests"
    },
    "python_versions": [
      "3",
      "3.12"
    ],
    "release_count": 155,
    "release_url": "https://pypi.org/project/requests/2.32.3/",
    "requires_python": ">=3.8",
    "source_url": "https://github.com/psf/requests",
    "summary": "Python HTTP for Humans.",
    "version": "2.32.3",
    "vulnerability_count": 0,
    "yanked_reason": null
  },
  "total_size": "191.7 KB",
  "total_size_bytes": 196288
}
```

### Get index statistics

Get how much storage PyPI holds in total and which hundred projects take up the most of it, largest first. The numbers behind 'PyPI is how many terabytes now?', and a way to see what a heavy dependency costs the index. No API key required.

**Inputs**

- Name contains (`name_contains`, text): Optional. Only projects whose name contains this text, for checking whether one in particular is in the top hundred. Leave blank for the whole leaderboard.
- Number of results (`limit`, number): Optional. How many projects to return. Between 1 and 100, which is the whole leaderboard; 25 by default. From 1 to 100. Default: `25`.

**Outputs**

- `count` (number): How many results are in this page.
- `has_more` (true/false): True when more results matched than this page holds.
- `largest_project` (text): The project at the top of the answer. Null when a name filter matched nothing.
- `name_contains` (text): The text the leaderboard was filtered by. Null when it was not filtered.
- `packages` (list): The projects using the most storage, largest first.
- `total_count` (number): How many results matched in total, across every page.
- `total_storage` (text): The same total written for people, e.g. 40.8 TB.
- `total_storage_bytes` (number): How much every file on PyPI takes up in total, in bytes.

**Example output**

```json
{
  "count": 1,
  "has_more": true,
  "largest_project": "tensorflow",
  "name_contains": null,
  "packages": [
    {
      "name": "tensorflow",
      "normalized_name": "tensorflow",
      "project_url": "https://pypi.org/project/tensorflow/",
      "rank": 1,
      "size": "392.2 GB",
      "size_bytes": 421123575981
    }
  ],
  "total_count": 100,
  "total_storage": "40.8 TB",
  "total_storage_bytes": 44861096544076
}
```

### Get new releases for a project

Get the releases a package has published, newest first, from the feed PyPI publishes for exactly this purpose. Pass the moment the last run finished and only what has appeared since comes back, so a scheduled workflow announces each release once. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Published after (`published_after`, date and time): Optional. Only items published after this moment. Pass the timestamp the previous run reported so a scheduled workflow sees each release exactly once. Leave blank for everything in the feed.
- Number of results (`limit`, number): Optional. How many results to return. The feed holds at most 100 items and is not pageable, so this is a cut rather than a page; 25 by default. From 1 to 100. Default: `25`.

**Outputs**

- `count` (number): How many results are in this page.
- `feed_size` (number): How many releases the feed held before filtering. PyPI keeps the most recent 40, so a project that publishes constantly needs checking more often than that.
- `has_more` (true/false): True when more results matched than this page holds.
- `has_new_releases` (true/false): True when anything was published after the moment given. Branch on this to stay quiet in between releases.
- `latest_published_at` (text): When that release went out. Store it and pass it back as Published after next run.
- `latest_version` (text): The newest version in the answer. Null when nothing was published since.
- `name` (text): The project that was watched.
- `project_url` (text): The project's page on pypi.org.
- `published_after` (text): The moment that was filtered from. Null when everything in the feed was returned.
- `releases` (list): The releases in this answer, newest first.
- `total_count` (number): How many results matched in total, across every page.

**Example output**

```json
{
  "count": 1,
  "feed_size": 40,
  "has_more": false,
  "has_new_releases": true,
  "latest_published_at": "2024-05-29T15:37:47Z",
  "latest_version": "2.32.3",
  "name": "requests",
  "project_url": "https://pypi.org/project/requests/",
  "published_after": "2024-05-01T00:00:00Z",
  "releases": [
    {
      "author": "me@kennethreitz.org",
      "is_prerelease": false,
      "published_at": "2024-05-29T15:37:47Z",
      "release_url": "https://pypi.org/project/requests/2.32.3/",
      "summary": "Python HTTP for Humans.",
      "version": "2.32.3"
    }
  ],
  "total_count": 1
}
```

### List dependencies

List what a package installs alongside itself. PyPI publishes dependencies as raw lines like 'urllib3<3,>=1.21.1; python_version < "3.11"'; each one comes back split into the package it names, the versions it accepts and the condition it applies under, so a workflow can act on it without parsing text. Optional groups are left out unless you ask for them. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text): Optional. Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published. Leave blank for the latest release.
- Optional groups (`extras`, list): Optional. Which optional dependency groups to include, the ones installed as 'pip install name[group]'. The list is fetched from PyPI, so it is always the groups this project offers.
- Include every optional group (`include_optional`, true/false): Optional. Include the dependencies of every optional group at once, instead of naming them above. Off by default. Default: `false`.

**Outputs**

- `count` (number): How many dependencies were selected.
- `dependencies` (list): The dependencies that were selected: the required ones, plus any optional groups asked for.
- `extras` (list): Every optional group the project offers, so a workflow can see what else it could ask for.
- `name` (text): The project these dependencies belong to.
- `optional_count` (number): How many belong to an optional group, whether or not that group was selected.
- `project_url` (text): The project's page on pypi.org.
- `required_count` (number): How many install with a plain 'pip install name'.
- `requires_python` (text): The Python versions the project itself installs into.
- `selected_extras` (list): The optional groups that were included.
- `version` (text): The version they were read from.

**Example output**

```json
{
  "count": 4,
  "dependencies": [
    {
      "extras": [],
      "is_optional": false,
      "marker": null,
      "name": "urllib3",
      "normalized_name": "urllib3",
      "project_url": "https://pypi.org/project/urllib3/",
      "required_for_extra": null,
      "requirement": "urllib3<3,>=1.21.1",
      "specifier": "<3,>=1.21.1"
    }
  ],
  "extras": [
    "socks",
    "use-chardet-on-py3"
  ],
  "name": "requests",
  "optional_count": 2,
  "project_url": "https://pypi.org/project/requests/",
  "required_count": 4,
  "requires_python": ">=3.8",
  "selected_extras": [],
  "version": "2.32.3"
}
```

### List distribution files

List the files a package has published: the wheels, the source distributions and anything else, each with the URL it downloads from, its size, its SHA-256 and whether PyPI holds signed provenance for it. Narrow it to one version or one kind of file. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text): Optional. Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published. Leave blank for the latest release.
- File types (`file_types`, list): Optional. Which kinds of file to return. Choose none for all of them. One or more of: `wheel` (Wheel (.whl) - the built package pip installs), `sdist` (Source distribution (.tar.gz or .zip)), `egg` (Egg (.egg) - the format wheels replaced), `windows_installer` (Windows installer (.exe or .msi)), `other` (Anything else (.rpm, .deb, .dmg)).
- Include withdrawn files (`include_yanked`, true/false): Optional. Include files that have been yanked. On by default. Default: `true`.
- Number of results (`limit`, number): Optional. How many results to return. Between 1 and 200; 25 by default. From 1 to 200. Default: `25`.
- Skip (`offset`, number): Optional. How many results to skip before this page. Use the next offset from the previous result to page through. 0 by default. At least 0. Default: `0`.

**Outputs**

- `count` (number): How many results are in this page.
- `files` (list): The files in this page, most recently uploaded first.
- `has_more` (true/false): True when more results matched than this page holds.
- `name` (text): The project these files belong to.
- `next_offset` (number): The offset that fetches the next page. Null when this is the last one.
- `project_url` (text): The project's page on pypi.org.
- `total_count` (number): How many results matched in total, across every page.
- `total_size` (text): The same combined size written for people.
- `total_size_bytes` (number): The combined size of every matching file, not just this page.
- `version` (text): The version the list was narrowed to. Null when every version is included.

**Example output**

```json
{
  "count": 1,
  "files": [
    {
      "file_type": "wheel",
      "filename": "requests-2.32.3-py3-none-any.whl",
      "has_provenance": false,
      "is_yanked": false,
      "md5": null,
      "provenance_url": null,
      "requires_python": ">=3.8",
      "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6",
      "size": "63.4 KB",
      "size_bytes": 64928,
      "uploaded_at": "2024-05-29T15:37:47Z",
      "url": "https://files.pythonhosted.org/packages/f9/9b/requests-2.32.3-py3-none-any.whl",
      "version": "2.32.3",
      "yanked_reason": null
    }
  ],
  "has_more": false,
  "name": "requests",
  "next_offset": null,
  "project_url": "https://pypi.org/project/requests/",
  "total_count": 2,
  "total_size": "191.7 KB",
  "total_size_bytes": 196288,
  "version": "2.32.3"
}
```

### List new projects

List the projects most recently registered on PyPI for the first time, from its own feed. Distinct from recent releases: these are names that did not exist before, which is what a typosquat watch or a 'what's new in Python' digest wants. No API key required.

**Inputs**

- Published after (`published_after`, date and time): Optional. Only items published after this moment. Pass the timestamp the previous run reported so a scheduled workflow sees each release exactly once. Leave blank for everything in the feed.
- Number of results (`limit`, number): Optional. How many results to return. The feed holds at most 100 items and is not pageable, so this is a cut rather than a page; 25 by default. From 1 to 100. Default: `25`.

**Outputs**

- `count` (number): How many results are in this page.
- `feed_size` (number): How many projects the feed held before filtering. PyPI keeps the most recent 40.
- `feed_url` (text): The feed this came from.
- `has_more` (true/false): True when more results matched than this page holds.
- `projects` (list): The projects in this answer, newest first.
- `published_after` (text): The moment that was filtered from. Null when everything in the feed was returned.
- `total_count` (number): How many results matched in total, across every page.

**Example output**

```json
{
  "count": 1,
  "feed_size": 40,
  "feed_url": "https://pypi.org/rss/packages.xml",
  "has_more": true,
  "projects": [
    {
      "name": "flaky-repro",
      "normalized_name": "flaky-repro",
      "project_url": "https://pypi.org/project/flaky-repro/",
      "registered_at": "2026-08-23T18:57:13Z",
      "summary": "A frequency-based flaky test diagnosis tool."
    }
  ],
  "published_after": null,
  "total_count": 40
}
```

### List recent releases

List the newest releases published anywhere on PyPI, from its own feed: the last hundred packages to ship a version, whatever they are. Use it to watch the ecosystem rather than one project. No API key required.

**Inputs**

- Published after (`published_after`, date and time): Optional. Only items published after this moment. Pass the timestamp the previous run reported so a scheduled workflow sees each release exactly once. Leave blank for everything in the feed.
- Number of results (`limit`, number): Optional. How many results to return. The feed holds at most 100 items and is not pageable, so this is a cut rather than a page; 25 by default. From 1 to 100. Default: `25`.

**Outputs**

- `count` (number): How many results are in this page.
- `feed_size` (number): How many releases the feed held before filtering. PyPI keeps the most recent 100, and publishes many a minute, so this covers roughly the last few minutes.
- `feed_url` (text): The feed this came from.
- `has_more` (true/false): True when more results matched than this page holds.
- `published_after` (text): The moment that was filtered from. Null when everything in the feed was returned.
- `releases` (list): The releases in this answer, newest first.
- `total_count` (number): How many results matched in total, across every page.

**Example output**

```json
{
  "count": 1,
  "feed_size": 100,
  "feed_url": "https://pypi.org/rss/updates.xml",
  "has_more": true,
  "published_after": null,
  "releases": [
    {
      "author": "me@kennethreitz.org",
      "is_prerelease": false,
      "name": "requests",
      "normalized_name": "requests",
      "project_url": "https://pypi.org/project/requests/",
      "published_at": "2024-05-29T15:37:47Z",
      "release_url": "https://pypi.org/project/requests/2.32.3/",
      "summary": "Python HTTP for Humans.",
      "version": "2.32.3"
    }
  ],
  "total_count": 100
}
```

### List releases

List every version a package has published, with the date it went out, how many files it shipped and whether it was a pre-release or has since been withdrawn. Filter to stable versions only, or to a window of dates, to build a changelog or see how often a project ships. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Include pre-releases (`include_prereleases`, true/false): Optional. Include alphas, betas, release candidates and dev builds. On by default; turn it off for the versions people actually install. Default: `true`.
- Include withdrawn releases (`include_yanked`, true/false): Optional. Include releases that have been yanked. On by default, because a yanked version is still installed anywhere it was pinned. Default: `true`.
- Released on or after (`released_after`, date): Optional. Only releases published on or after this date.
- Released on or before (`released_before`, date): Optional. Only releases published on or before this date.
- Order (`sort`, text): Optional. Which end of the history to start from. Newest first by default. Versions are ordered the way Python orders them, so 0.10 comes after 0.9. One of: `newest_first` (Newest version first), `oldest_first` (Oldest version first). Default: `newest_first`.
- Number of results (`limit`, number): Optional. How many results to return. Between 1 and 200; 25 by default. From 1 to 200. Default: `25`.
- Skip (`offset`, number): Optional. How many results to skip before this page. Use the next offset from the previous result to page through. 0 by default. At least 0. Default: `0`.

**Outputs**

- `count` (number): How many results are in this page.
- `has_more` (true/false): True when more results matched than this page holds.
- `latest_version` (text): The newest stable version among the releases that matched. Null when the filters left only pre-releases.
- `name` (text): The project these releases belong to.
- `next_offset` (number): The offset that fetches the next page. Null when this is the last one.
- `project_url` (text): The project's page on pypi.org.
- `releases` (list): The releases in this page.
- `total_count` (number): How many results matched in total, across every page.

**Example output**

```json
{
  "count": 1,
  "has_more": true,
  "latest_version": "2.32.3",
  "name": "requests",
  "next_offset": 25,
  "project_url": "https://pypi.org/project/requests/",
  "releases": [
    {
      "file_count": 2,
      "has_sdist": true,
      "has_wheel": true,
      "is_prerelease": false,
      "is_yanked": false,
      "release_url": "https://pypi.org/project/requests/2.32.3/",
      "released_at": "2024-05-29T15:37:47Z",
      "requires_python": ">=3.8",
      "total_size": "191.7 KB",
      "total_size_bytes": 196288,
      "version": "2.32.3",
      "yanked_reason": null
    }
  ],
  "total_count": 155
}
```

### List security advisories

List the known security advisories for a package, from the Open Source Vulnerability database PyPI reports from. Ask about a specific version to check something a project has pinned; each advisory says what the issue is, which versions fix it and where to read more. No API key required.

**Inputs**

- Project name (`project`, text, required): The package's name on PyPI, e.g. requests. Capitals, dots, hyphens and underscores are all treated the same, so 'Zope.Interface' and 'zope-interface' reach the same project.
- Version (`version`, text): Optional. Which version to read. The list is fetched from PyPI, so it is always the versions this project actually published. Leave blank for the latest release.
- Include retracted advisories (`include_withdrawn`, true/false): Optional. Include advisories that have since been retracted. Off by default, since a retracted advisory is not something to act on. Default: `false`.

**Outputs**

- `checked_specific_version` (true/false): True when a version was named, false when the latest release was checked.
- `count` (number): How many advisories apply.
- `fixed_versions` (list): Every version named as fixing one of these advisories, oldest first: the shortlist of places to upgrade to.
- `is_affected` (true/false): True when at least one advisory applies. Branch on this to alert only when there is something to say.
- `name` (text): The project that was checked.
- `project_url` (text): The project's page on pypi.org.
- `release_url` (text): That version's page on pypi.org.
- `version` (text): The version the advisories apply to.
- `vulnerabilities` (list): The advisories that apply to the version checked.

**Example output**

```json
{
  "checked_specific_version": true,
  "count": 1,
  "fixed_versions": [
    "1.26.5"
  ],
  "is_affected": true,
  "name": "urllib3",
  "project_url": "https://pypi.org/project/urllib3/",
  "release_url": "https://pypi.org/project/urllib3/1.26.4/",
  "version": "1.26.4",
  "vulnerabilities": [
    {
      "aliases": [
        "CVE-2021-33503",
        "GHSA-q2q7-5pp4-w6pg"
      ],
      "cve_ids": [
        "CVE-2021-33503"
      ],
      "details": "An issue was discovered in urllib3 before 1.26.5: a URL with many @ characters causes catastrophic backtracking.",
      "fixed_in": [
        "1.26.5"
      ],
      "id": "PYSEC-2021-108",
      "is_fixed": true,
      "is_withdrawn": false,
      "link": "https://osv.dev/vulnerability/PYSEC-2021-108",
      "source": "osv",
      "summary": null,
      "withdrawn": null
    }
  ]
}
```

### Search projects

Find projects whose name contains, starts with, ends with or exactly matches some text. PyPI publishes no full-text search, so this matches names rather than descriptions: it is the step for 'is there a package called something like this?'. Matching ignores capitals and treats '-', '_' and '.' as the same character, exactly as PyPI does. No API key required.

**Inputs**

- Search text (`query`, text, required): The text to look for in project names, e.g. 'pytest-' to find pytest plugins.
- Match (`match`, text): Optional. How the text must match the name. Contains by default. One of: `contains` (Contains the text), `starts_with` (Starts with the text), `ends_with` (Ends with the text), `exact` (Is exactly the text). Default: `contains`.
- Number of results (`limit`, number): Optional. How many results to return. Between 1 and 200; 25 by default. From 1 to 200. Default: `25`.
- Skip (`offset`, number): Optional. How many results to skip before this page. Use the next offset from the previous result to page through. 0 by default. At least 0. Default: `0`.

**Outputs**

- `count` (number): How many results are in this page.
- `has_more` (true/false): True when more results matched than this page holds.
- `match` (text): How the text was matched.
- `match_limit_reached` (true/false): True when the search stopped at 1,000 matches, so more exist. Narrow the text or switch to Starts with.
- `next_offset` (number): The offset that fetches the next page. Null when this is the last one.
- `projects` (list): The matching projects in this page, shortest name first.
- `projects_scanned` (number): How many project names were read: every one on PyPI, which is around 900,000.
- `query` (text): The text that was searched for.
- `total_count` (number): How many results matched in total, across every page.

**Example output**

```json
{
  "count": 1,
  "has_more": false,
  "match": "contains",
  "match_limit_reached": false,
  "next_offset": null,
  "projects": [
    {
      "name": "pandas-profiling",
      "normalized_name": "pandas-profiling",
      "project_url": "https://pypi.org/project/pandas-profiling/"
    }
  ],
  "projects_scanned": 876758,
  "query": "pandas-profil",
  "total_count": 5
}
```
