On this page

API

Versions operations

Immutable published versions, bundles and install descriptors.

Immutable published versions, bundles and install descriptors. Paths are relative to https://reuseforge.com/api/v1.

Operations in this area
OperationMethodPath
Install descriptorGET/items/{owner}/{slug}/install
List versionsGET/items/{owner}/{slug}/versions
Publish a versionPOST/items/{owner}/{slug}/versions
Get a versionGET/items/{owner}/{slug}/versions/{version}
Yank or restore a versionPATCH/items/{owner}/{slug}/versions/{version}
Download a versionGET/items/{owner}/{slug}/versions/{version}/bundle

Install descriptor

GET /items/{owner}/{slug}/install Enabled on reuseforge.com

A machine-readable recipe for installing a version into a specific agent environment: files to write, config to merge, commands to show, and the reuseforge.lock entry. Free items work anonymously. Paid items return 402 payment_required with an order_hint until your account is entitled (an order for the item is delivered, disputed or released and not refunded). A quarantined version answers 403 version_quarantined (see get_version_bundle). The descriptor itself contains no file contents: fetch them with get_version_bundle. Fetching it while signed in records an install, which makes you eligible to review free items.

Install descriptor: facts
PropertyValue
Operation IDget_install_descriptor
AuthenticationNone required. A token raises your rate limits and shows your private items.
Rate tierread: 60/min per IP anonymous, 600/min per token with a token
Python SDKclient.get_install_descriptor(...)
JavaScript SDKclient.getInstallDescriptor(...)
CLIrf items descriptor
MCP toolget_install_descriptor
Deploymentsreuseforge.com: enabled. Python node: implemented.

Parameters

Install descriptor: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
targetqueryInstallTargetnoWhere the item will be installed.
versionquerystringnoExact version or latest (default). Default "latest".

Responses

Install descriptor: responses
StatusMeaningBody
200 OKThe descriptor.application/json: InstallDescriptor
400The request is malformed (bad JSON, unknown or mistyped parameter, invalid cursor).Problem. Codes: invalid_request, invalid_json, invalid_parameter, invalid_cursor, idempotency_key_required
402The item is paid and the caller is not entitled. order_hint says exactly what to order.Problem. Codes: payment_required
403Authenticated, but not allowed. Most often a missing scope (insufficient_scope, with required_scopes), an exceeded spend limit, or a role on the owning account that is too low. Also version_quarantined (the security scan or a moderator blocked the version you asked for) and review_removed (a moderator removed your review).Problem. Codes: insufficient_scope, forbidden, account_suspended, email_unverified, spend_limit_exceeded, purchase_required, quota_exceeded, version_quarantined, review_removed
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
410The resource existed and is permanently unavailable (retracted item, expired plan).Problem. Codes: gone, plan_expired
422The body is well-formed JSON but invalid (validation_failed with per-field errors), or a business rule rejects it (payment_invalid, webhook_url_forbidden, idempotency_key_reuse).Problem. Codes: validation_failed, payment_invalid, rail_unsupported, idempotency_key_reuse, webhook_url_forbidden, invalid_signature, integrity_mismatch
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/install'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

result = client.get_install_descriptor("acme/invoice-extractor")
print(result)

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

const result = await client.getInstallDescriptor("acme/invoice-extractor");
console.log(result);

CLI

bash
rf items descriptor acme/invoice-extractor

# rf items descriptor <item> [options]
# all options: rf items descriptor --help

Response 200 OK:

json
{
  "object": "install_descriptor",
  "item": "acme/invoice-extractor",
  "item_id": "itm_invoiceextr2",
  "kind": "skill",
  "version": "1.4.0",
  "target": "claude-code",
  "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
  "license": "MIT",
  "price_cents": 0,
  "currency": "USD",
  "entitlement": {
    "required": false,
    "granted": true,
    "reason": "free",
    "order_id": null
  },
  "bundle_url": "https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions/1.4.0/bundle",
  "files": [
    {
      "path": ".claude/skills/invoice-extractor/SKILL.md",
      "source_path": "SKILL.md",
      "sha256": "0d513c7b5ef7777ab855c1d1608db8916080485038901daa59524757549540a2",
      "size_bytes": 2210,
      "mode": "0644"
    },
    {
      "path": ".claude/skills/invoice-extractor/src/extract.py",
      "source_path": "src/extract.py",
      "sha256": "75737d9d063bc4d4ac1613bc16d49e275727cf548a7e6eb029ac6087d22a24c6",
      "size_bytes": 41876,
      "mode": "0644"
    },
    {
      "path": ".claude/skills/invoice-extractor/README.md",
      "source_path": "README.md",
      "sha256": "42c59af8a4bae559bc5a5d5d3f06f02ee30e2afcd9f2d0c39b38ccee6d0fa9b8",
      "size_bytes": 4127,
      "mode": "0644"
    }
  ],
  "config_patches": [],
  "commands": [],
  "lock_entry": {
    "name": "acme/invoice-extractor",
    "id": "itm_invoiceextr2",
    "version": "1.4.0",
    "kind": "skill",
    "target": "claude-code",
    "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
    "license": "MIT",
    "source": "reuseforge",
    "order_id": null,
    "price_paid_cents": 0,
    "files": [
      {
        "path": ".claude/skills/invoice-extractor/SKILL.md",
        "sha256": "0d513c7b5ef7777ab855c1d1608db8916080485038901daa59524757549540a2"
      },
      {
        "path": ".claude/skills/invoice-extractor/src/extract.py",
        "sha256": "75737d9d063bc4d4ac1613bc16d49e275727cf548a7e6eb029ac6087d22a24c6"
      },
      {
        "path": ".claude/skills/invoice-extractor/README.md",
        "sha256": "42c59af8a4bae559bc5a5d5d3f06f02ee30e2afcd9f2d0c39b38ccee6d0fa9b8"
      }
    ]
  },
  "notes": [
    "Restart Claude Code to load the skill."
  ],
  "warnings": []
}

List versions

GET /items/{owner}/{slug}/versions Enabled on reuseforge.com

Published versions, newest (by semantic version) first, including yanked ones (flagged).

List versions: facts
PropertyValue
Operation IDlist_versions
AuthenticationNone required. A token raises your rate limits and shows your private items.
Rate tierread: 60/min per IP anonymous, 600/min per token with a token
Python SDKclient.list_versions(...)
JavaScript SDKclient.listVersions(...)
CLIrf versions list
MCP toollist_versions
Deploymentsreuseforge.com: enabled. Python node: implemented.

Parameters

List versions: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
cursorquerystringnoOpaque cursor from the previous page's next_cursor.
limitqueryintegernoPage size. Default 30.

Responses

List versions: responses
StatusMeaningBody
200 OKA page of versions without file lists.application/json: ItemVersionPage
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

for entry in client.list_versions("acme/invoice-extractor"):  # iterating fetches further pages on demand
    print(entry["id"])

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

for await (const entry of client.listVersions("acme/invoice-extractor")) {  // iterating fetches further pages on demand
  console.log(entry.id);
}

CLI

bash
rf versions list acme/invoice-extractor

# rf versions list <item> [options]
# all options: rf versions list --help

Response 200 OK:

json
{
  "data": [
    {
      "id": "ver_xinvoice2345",
      "object": "item_version",
      "item": "acme/invoice-extractor",
      "item_id": "itm_invoiceextr2",
      "version": "1.4.0",
      "changelog": "Adds multi-currency totals and a --strict mode.",
      "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
      "size_bytes": 48213,
      "file_count": 3,
      "dependencies": [
        {
          "item": "acme/pdf-text-layer",
          "range": "^2.0.0"
        }
      ],
      "yanked": false,
      "yanked_reason": null,
      "prerelease": false,
      "archive_sha256": "a3c0f5bd09a1d7b4e2f8c61d9b7e45a0c1f3d2e8b6a49f7c05d1e3b28a6c4f90",
      "manifest": null,
      "created_by": {
        "id": "acc_acmelabsorg2",
        "type": "org",
        "handle": "acme",
        "display_name": "Acme Labs",
        "verified": true,
        "avatar_url": ""
      },
      "created_at": "2026-10-28T09:10:02Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Publish a version

POST /items/{owner}/{slug}/versions Enabled on reuseforge.com

Publishes an immutable version. Versions are semantic versions (MAJOR.MINOR.PATCH[-prerelease]), must be unique per item and can never be overwritten; correct a mistake by publishing a higher version and yanking the bad one. Limits: 100 files, 512 KiB per file, 2 MiB per version (see get_api_index), and a storage quota per owning account over all its items (20 MB unverified, 200 MB verified email, 1 GB verified publisher); a version that does not fit answers 413 quota_exceeded and stores nothing. The version is scanned for malware patterns before the answer; a blocked version is quarantined (see get_version_bundle). Paths are relative, use /, and may not contain ... If content_hash is sent, the server recomputes it and answers 422 on mismatch. Fires item.version.published (and item.published for the first public version).

Publish a version: facts
PropertyValue
Operation IDpublish_version
AuthenticationBearer token holding items:publish
Rate tierwrite: not allowed anonymous, 120/min per token with a token
IdempotencyIdempotency-Key header, optional. The SDKs and the CLI send one for you.
Python SDKclient.publish_version(...)
JavaScript SDKclient.publishVersion(...)
CLIrf versions publish
MCP toolpublish_version
Deploymentsreuseforge.com: enabled. Python node: not implemented (answers 501).

Parameters

Publish a version: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
Idempotency-KeyheaderstringnoClient-chosen unique key (1 to 255 printable ASCII characters, a UUID is ideal). A repeat of the same request with the same key within 24 hours returns the first response with Idempotent-Replayed: true. The same key with a different body returns 422 idempotency_key_reuse; a repeat while the first call is still running returns 409 idempotency_in_progress.

Request body

application/json, required, schema VersionCreate

Publish a version: request fields
FieldTypeRequiredDescription
versionstringyes
changelogstringno
filesarray of FileInputyes
dependenciesarray of Dependencyno
manifestobjectnoContents of reuseforge.json (schema: api/schemas/reuseforge.schema.json). Validated and stored.
content_hashContentHashnoSHA-256 over the text made of one line <sha256 of file bytes> <path> per file (two spaces, \n after each line), files sorted by path in UTF-8 byte order. Identical to the output of sha256sum over the files, so it can be recomputed with standard tools.

Responses

Publish a version: responses
StatusMeaningBody
201 CreatedThe published version.application/json: ItemVersion
400The request is malformed (bad JSON, unknown or mistyped parameter, invalid cursor).Problem. Codes: invalid_request, invalid_json, invalid_parameter, invalid_cursor, idempotency_key_required
401Missing, malformed, expired or revoked credentials.Problem. Codes: unauthorized, invalid_token, token_expired
403Authenticated, but not allowed. Most often a missing scope (insufficient_scope, with required_scopes), an exceeded spend limit, or a role on the owning account that is too low. Also version_quarantined (the security scan or a moderator blocked the version you asked for) and review_removed (a moderator removed your review).Problem. Codes: insufficient_scope, forbidden, account_suspended, email_unverified, spend_limit_exceeded, purchase_required, quota_exceeded, version_quarantined, review_removed
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
409The request conflicts with current state (duplicate resource, wrong lifecycle state, idempotency conflict).Problem. Codes: conflict, already_exists, invalid_state, idempotency_in_progress
413The body or a file exceeds a limit published in get_api_index.Problem. Codes: payload_too_large
422The body is well-formed JSON but invalid (validation_failed with per-field errors), or a business rule rejects it (payment_invalid, webhook_url_forbidden, idempotency_key_reuse).Problem. Codes: validation_failed, payment_invalid, rail_unsupported, idempotency_key_reuse, webhook_url_forbidden, invalid_signature, integrity_mismatch
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl -X POST 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions' \
  -H "Authorization: Bearer $REUSEFORGE_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "version": "1.4.0",
  "changelog": "Adds multi-currency totals and a --strict mode.",
  "files": [
    {
      "path": "SKILL.md",
      "content": "---\nname: invoice-extractor\ndescription: Extract invoice fields from PDFs.\n---\n\nRun src/extract.py on a PDF.\n",
      "encoding": "utf8",
      "content_type": "text/markdown",
      "preview": true
    },
    {
      "path": "src/extract.py",
      "content": "import sys\n\nprint('\''extract'\'', sys.argv[1:])\n",
      "encoding": "utf8",
      "content_type": "text/x-python"
    }
  ],
  "dependencies": [
    {
      "item": "acme/pdf-text-layer",
      "range": "^2.0.0"
    }
  ],
  "manifest": {
    "name": "acme/invoice-extractor",
    "version": "1.4.0",
    "kind": "skill"
  }
}'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

result = client.publish_version(
    "acme/invoice-extractor",
    version="1.4.0",
    changelog="Adds multi-currency totals and a --strict mode.",
    files=[
            {
                "path": "SKILL.md",
                "content": "---\nname: invoice-extractor\ndescription: Extract invoice fields from PDFs.\n---\n\nRun src/extract.py on a PDF.\n",
                "encoding": "utf8",
                "content_type": "text/markdown",
                "preview": True,
            },
            {
                "path": "src/extract.py",
                "content": "import sys\n\nprint('extract', sys.argv[1:])\n",
                "encoding": "utf8",
                "content_type": "text/x-python",
            },
        ],
    dependencies=[{"item": "acme/pdf-text-layer", "range": "^2.0.0"}],
    manifest={"name": "acme/invoice-extractor", "version": "1.4.0", "kind": "skill"},
)
print(result["id"])

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

const result = await client.publishVersion("acme/invoice-extractor", {
  version: "1.4.0",
  changelog: "Adds multi-currency totals and a --strict mode.",
  files: [
    {
      path: "SKILL.md",
      content: "---\nname: invoice-extractor\ndescription: Extract invoice fields from PDFs.\n---\n\nRun src/extract.py on a PDF.\n",
      encoding: "utf8",
      content_type: "text/markdown",
      preview: true,
    },
    {
      path: "src/extract.py",
      content: "import sys\n\nprint('extract', sys.argv[1:])\n",
      encoding: "utf8",
      content_type: "text/x-python",
    },
  ],
  dependencies: [{ item: "acme/pdf-text-layer", range: "^2.0.0" }],
  manifest: { name: "acme/invoice-extractor", version: "1.4.0", kind: "skill" },
});
console.log(result.id);

CLI

bash
rf versions publish

# rf versions publish [options]
# all options: rf versions publish --help

Response 201 Created:

json
{
  "id": "ver_xinvoice2345",
  "object": "item_version",
  "item": "acme/invoice-extractor",
  "item_id": "itm_invoiceextr2",
  "version": "1.4.0",
  "changelog": "Adds multi-currency totals and a --strict mode.",
  "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
  "size_bytes": 48213,
  "file_count": 3,
  "dependencies": [
    {
      "item": "acme/pdf-text-layer",
      "range": "^2.0.0"
    }
  ],
  "yanked": false,
  "yanked_reason": null,
  "prerelease": false,
  "archive_sha256": "a3c0f5bd09a1d7b4e2f8c61d9b7e45a0c1f3d2e8b6a49f7c05d1e3b28a6c4f90",
  "manifest": null,
  "created_by": {
    "id": "acc_acmelabsorg2",
    "type": "org",
    "handle": "acme",
    "display_name": "Acme Labs",
    "verified": true,
    "avatar_url": ""
  },
  "created_at": "2026-10-28T09:10:02Z"
}

Get a version

GET /items/{owner}/{slug}/versions/{version} Enabled on reuseforge.com

One version with its file list (paths, sizes, hashes; contents only through the bundle). latest resolves to the highest non-yanked, non-quarantined stable version, or, only when the item has no stable version, the highest live prerelease. For a quarantined version (see get_version_bundle) callers who do not manage the item receive the version without files, manifest and verification.

Get a version: facts
PropertyValue
Operation IDget_version
AuthenticationNone required. A token raises your rate limits and shows your private items.
Rate tierread: 60/min per IP anonymous, 600/min per token with a token
Python SDKclient.get_version(...)
JavaScript SDKclient.getVersion(...)
CLIrf versions get
MCP toolget_version
Deploymentsreuseforge.com: enabled. Python node: implemented.

Parameters

Get a version: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
versionpathstringyesAn exact semantic version or latest.

Responses

Get a version: responses
StatusMeaningBody
200 OKThe version.application/json: ItemVersion
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions/1.4.0'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

result = client.get_version("acme/invoice-extractor", "1.4.0")
print(result["id"])

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

const result = await client.getVersion("acme/invoice-extractor", "1.4.0");
console.log(result.id);

CLI

bash
rf versions get acme/invoice-extractor 1.4.0

# rf versions get <item> [version]
# all options: rf versions get --help

Response 200 OK:

json
{
  "id": "ver_xinvoice2345",
  "object": "item_version",
  "item": "acme/invoice-extractor",
  "item_id": "itm_invoiceextr2",
  "version": "1.4.0",
  "changelog": "Adds multi-currency totals and a --strict mode.",
  "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
  "size_bytes": 48213,
  "file_count": 3,
  "files": [
    {
      "path": "SKILL.md",
      "size_bytes": 2210,
      "sha256": "0d513c7b5ef7777ab855c1d1608db8916080485038901daa59524757549540a2",
      "content_type": "text/markdown",
      "preview": true
    },
    {
      "path": "src/extract.py",
      "size_bytes": 41876,
      "sha256": "75737d9d063bc4d4ac1613bc16d49e275727cf548a7e6eb029ac6087d22a24c6",
      "content_type": "text/x-python",
      "preview": false
    },
    {
      "path": "README.md",
      "size_bytes": 4127,
      "sha256": "42c59af8a4bae559bc5a5d5d3f06f02ee30e2afcd9f2d0c39b38ccee6d0fa9b8",
      "content_type": "text/markdown",
      "preview": true
    }
  ],
  "dependencies": [
    {
      "item": "acme/pdf-text-layer",
      "range": "^2.0.0"
    }
  ],
  "yanked": false,
  "yanked_reason": null,
  "prerelease": false,
  "manifest": null,
  "verification": {
    "id": "vrf_testrun22222",
    "object": "verification",
    "item": "acme/invoice-extractor",
    "version": "1.4.0",
    "state": "passed",
    "runner": "platform",
    "tests_total": 64,
    "tests_passed": 62,
    "tests_pass_rate": 0.97,
    "summary": "62 of 64 tests passed on Python 3.12.",
    "created_at": "2026-10-28T09:11:00Z",
    "completed_at": "2026-10-28T09:12:40Z"
  },
  "created_by": {
    "id": "acc_acmelabsorg2",
    "type": "org",
    "handle": "acme",
    "display_name": "Acme Labs",
    "verified": true,
    "avatar_url": ""
  },
  "created_at": "2026-10-28T09:10:02Z"
}

Yank or restore a version

PATCH /items/{owner}/{slug}/versions/{version} Enabled on reuseforge.com

Yanking hides a version from latest resolution and warns installers, but never deletes content, so existing lockfiles still resolve. Only changelog, yanked and yanked_reason can change. Fires item.updated.

Yank or restore a version: facts
PropertyValue
Operation IDupdate_version
AuthenticationBearer token holding items:publish
Rate tierwrite: not allowed anonymous, 120/min per token with a token
Python SDKclient.update_version(...)
JavaScript SDKclient.updateVersion(...)
CLIrf versions yank
MCP toolupdate_version
Deploymentsreuseforge.com: enabled. Python node: not implemented (answers 501).

Parameters

Yank or restore a version: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
versionpathstringyesAn exact semantic version or latest.

Request body

application/json, required, schema VersionUpdate

Yank or restore a version: request fields
FieldTypeRequiredDescription
changelogstringno
yankedbooleanno
yanked_reasonstring or nullno

Responses

Yank or restore a version: responses
StatusMeaningBody
200 OKThe updated version.application/json: ItemVersion
400The request is malformed (bad JSON, unknown or mistyped parameter, invalid cursor).Problem. Codes: invalid_request, invalid_json, invalid_parameter, invalid_cursor, idempotency_key_required
401Missing, malformed, expired or revoked credentials.Problem. Codes: unauthorized, invalid_token, token_expired
403Authenticated, but not allowed. Most often a missing scope (insufficient_scope, with required_scopes), an exceeded spend limit, or a role on the owning account that is too low. Also version_quarantined (the security scan or a moderator blocked the version you asked for) and review_removed (a moderator removed your review).Problem. Codes: insufficient_scope, forbidden, account_suspended, email_unverified, spend_limit_exceeded, purchase_required, quota_exceeded, version_quarantined, review_removed
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
422The body is well-formed JSON but invalid (validation_failed with per-field errors), or a business rule rejects it (payment_invalid, webhook_url_forbidden, idempotency_key_reuse).Problem. Codes: validation_failed, payment_invalid, rail_unsupported, idempotency_key_reuse, webhook_url_forbidden, invalid_signature, integrity_mismatch
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl -X PATCH 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions/1.4.0' \
  -H "Authorization: Bearer $REUSEFORGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "yanked": true,
  "yanked_reason": "Crashes on invoices without a total line."
}'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

result = client.update_version(
    "acme/invoice-extractor",
    "1.4.0",
    yanked=True,
    yanked_reason="Crashes on invoices without a total line.",
)
print(result["id"])

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

const result = await client.updateVersion("acme/invoice-extractor", "1.4.0", { yanked: true, yanked_reason: "Crashes on invoices without a total line." });
console.log(result.id);

CLI

bash
rf versions yank acme/invoice-extractor 1.4.0

# rf versions yank <item> <version> [options]
# all options: rf versions yank --help

Response 200 OK:

json
{
  "id": "ver_xinvoice2345",
  "object": "item_version",
  "item": "acme/invoice-extractor",
  "item_id": "itm_invoiceextr2",
  "version": "1.4.0",
  "changelog": "Adds multi-currency totals and a --strict mode.",
  "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
  "size_bytes": 48213,
  "file_count": 3,
  "dependencies": [],
  "yanked": true,
  "yanked_reason": "Crashes on invoices without a total line.",
  "prerelease": false,
  "manifest": null,
  "created_by": {
    "id": "acc_acmelabsorg2",
    "type": "org",
    "handle": "acme",
    "display_name": "Acme Labs",
    "verified": true,
    "avatar_url": ""
  },
  "created_at": "2026-10-28T09:10:02Z"
}

Download a version

GET /items/{owner}/{slug}/versions/{version}/bundle Enabled on reuseforge.com

All files of a version in one JSON document (at most 2 MiB of content, base64 for binary files). Clients must verify every sha256 and the content_hash. Paid versions return 402 payment_required until you are entitled, except for files flagged preview. A quarantined version (the security scan blocked it and no administrator allowed it, or an administrator blocked it) answers 403 version_quarantined to everybody except the owner, members of the owning account with write access and administrators; the check runs before the entitlement check.

Download a version: facts
PropertyValue
Operation IDget_version_bundle
AuthenticationNone required. A token raises your rate limits and shows your private items.
Rate tierread: 60/min per IP anonymous, 600/min per token with a token
Python SDKclient.get_version_bundle(...)
JavaScript SDKclient.getVersionBundle(...)
CLIrf versions download
MCP toolnot exposed as a tool
Deploymentsreuseforge.com: enabled. Python node: implemented.

Parameters

Download a version: parameters
NameInTypeRequiredDescription
ownerpathstringyesHandle of the owning user or organization.
slugpathstringyesItem slug, unique per owner.
versionpathstringyesAn exact semantic version or latest.

Responses

Download a version: responses
StatusMeaningBody
200 OKThe bundle.application/json: Bundle
402The item is paid and the caller is not entitled. order_hint says exactly what to order.Problem. Codes: payment_required
403Authenticated, but not allowed. Most often a missing scope (insufficient_scope, with required_scopes), an exceeded spend limit, or a role on the owning account that is too low. Also version_quarantined (the security scan or a moderator blocked the version you asked for) and review_removed (a moderator removed your review).Problem. Codes: insufficient_scope, forbidden, account_suspended, email_unverified, spend_limit_exceeded, purchase_required, quota_exceeded, version_quarantined, review_removed
404No such resource, or it is private and the caller may not know it exists.Problem. Codes: not_found
429Rate limit for the operation's tier exceeded. Wait Retry-After seconds.Problem. Codes: rate_limited

Example

curl

bash
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions/1.4.0/bundle'

Python

python
import reuseforge

client = reuseforge.Client()  # token from REUSEFORGE_TOKEN, or the file `rf login` wrote

result = client.get_version_bundle("acme/invoice-extractor", "1.4.0")
print(result)

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });

const result = await client.getVersionBundle("acme/invoice-extractor", "1.4.0");
console.log(result);

CLI

bash
rf versions download acme/invoice-extractor 1.4.0

# rf versions download <item> [version] [options]
# all options: rf versions download --help

Response 200 OK:

json
{
  "item": "acme/invoice-extractor",
  "version": "1.4.0",
  "content_hash": "sha256:ea91565182d4a3fde4c71e4bc8ba34dd057a9717707652e8916f7559500f6c8c",
  "files": [
    {
      "path": "SKILL.md",
      "content": "---\nname: invoice-extractor\ndescription: Extract invoice fields from PDFs.\n---\n\nRun src/extract.py on a PDF.\n",
      "encoding": "utf8",
      "sha256": "0d513c7b5ef7777ab855c1d1608db8916080485038901daa59524757549540a2",
      "size_bytes": 2210,
      "content_type": "text/markdown"
    }
  ]
}