API

Ledger operations

Signed event feed for syncing self-hosted nodes with the hosted platform.

Signed event feed for syncing self-hosted nodes with the hosted platform. Paths are relative to https://reuseforge.com/api/v1.

Operations in this area
OperationMethodPath
Read the signed event feedGET/ledger/events
Push signed eventsPOST/ledger/events

Read the signed event feed

GET /ledger/events Not enabled on reuseforge.com yet

The append-only feed of signed ledger events (item publications and retractions, reviews, attestations and project events) used to synchronise self-hosted nodes with the hosted platform. Events are immutable and content-addressed; take the union to merge. Pass next_cursor as since to continue; an empty since starts from the beginning. Order events are served only to their participants.

Read the signed event feed: facts
PropertyValue
Operation IDlist_ledger_events
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_ledger_events(...)
JavaScript SDKclient.listLedgerEvents(...)
CLIrf ledger pull
MCP toolnot exposed as a tool
Deploymentsreuseforge.com: not enabled yet (answers 501 not_implemented). Python node: implemented.

Parameters

Read the signed event feed: parameters
NameInTypeRequiredDescription
sincequerystringnoOpaque cursor returned as next_cursor by the previous call.
kindqueryarray of stringnoOnly these event kinds (comma separated), for example block.publish,review.
limitqueryintegernoDefault 200.

Responses

Read the signed event feed: responses
StatusMeaningBody
200 OKEvents in ledger order.application/json: LedgerEventPage
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
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/ledger/events'

Python

python
import reuseforge

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

result = client.list_ledger_events()
print(result["id"])

JavaScript

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

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

const result = await client.listLedgerEvents();
console.log(result.id);

CLI

bash
rf ledger pull

# rf ledger pull [options]
# all options: rf ledger pull --help

Response 200 OK:

json
{
  "data": [
    {
      "id": "3c6e1f0b9a7d42885e1c0a9f3b2d4e6a8c0b1d3f5a7c9e2b4d6f8a0c1e3b5d79",
      "body": {
        "kind": "block.publish",
        "author": "rb1Qm3pX0vN8cT2yJ4kL6hD9sA1fG5wE7uB3iZ0oR2tY",
        "data": {
          "name": "Invoice extractor",
          "kind": "skill",
          "summary": "Extracts vendor totals and line items from PDF invoices.",
          "url": "https://github.com/acme/invoice-extractor",
          "capabilities": [
            "document-parsing"
          ],
          "license": "MIT",
          "price_usd": 0,
          "version": "1.4.0"
        },
        "lamport": 1042,
        "parents": [
          "8a1d0c7e5b3f9a2d4c6e8b0a1d3f5c7e9b2a4d6f8c0e1a3b5d7f9c2e4a6b8d01"
        ],
        "ts": 1793700000
      },
      "sig": "4Z8mQeV1xJr0Sk9TnC3bHdW5yLfA7uPoGi2EtRaN6vXcM1sKjDq8YhBlOw0UzFg3ItPe5CnSvHrA9dJk2LmQxT4bWy7NuE1ZoGf6RiCa"
    }
  ],
  "next_cursor": "lamport-1042",
  "has_more": false
}

Push signed events

POST /ledger/events Not enabled on reuseforge.com yet

Submits events from a peer node. Each event is verified (hash, Ed25519 signature) and folded independently: invalid or unauthorised events are reported in rejected and never block the rest, and already known events count as duplicates. At most 500 events and 3 MiB per request.

Push signed events: facts
PropertyValue
Operation IDpost_ledger_events
AuthenticationBearer token holding items:write
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.post_ledger_events(...)
JavaScript SDKclient.postLedgerEvents(...)
CLIrf ledger push
MCP toolnot exposed as a tool
Deploymentsreuseforge.com: not enabled yet (answers 501 not_implemented). Python node: implemented.

Parameters

Push signed events: parameters
NameInTypeRequiredDescription
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 LedgerEventsPush

Push signed events: request fields
FieldTypeRequiredDescription
eventsarray of LedgerEventyes

Responses

Push signed events: responses
StatusMeaningBody
200 OKResult per batch.application/json: LedgerPushResult
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
413The body or a file exceeds a limit published in get_api_index.Problem. Codes: payload_too_large
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/ledger/events' \
  -H "Authorization: Bearer $REUSEFORGE_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "events": [
    {
      "id": "3c6e1f0b9a7d42885e1c0a9f3b2d4e6a8c0b1d3f5a7c9e2b4d6f8a0c1e3b5d79",
      "body": {
        "kind": "block.publish",
        "author": "rb1Qm3pX0vN8cT2yJ4kL6hD9sA1fG5wE7uB3iZ0oR2tY",
        "data": {
          "name": "Invoice extractor",
          "kind": "skill",
          "summary": "Extracts vendor totals and line items from PDF invoices.",
          "url": "https://github.com/acme/invoice-extractor",
          "capabilities": [
            "document-parsing"
          ],
          "license": "MIT",
          "price_usd": 0,
          "version": "1.4.0"
        },
        "lamport": 1042,
        "parents": [
          "8a1d0c7e5b3f9a2d4c6e8b0a1d3f5c7e9b2a4d6f8c0e1a3b5d7f9c2e4a6b8d01"
        ],
        "ts": 1793700000
      },
      "sig": "4Z8mQeV1xJr0Sk9TnC3bHdW5yLfA7uPoGi2EtRaN6vXcM1sKjDq8YhBlOw0UzFg3ItPe5CnSvHrA9dJk2LmQxT4bWy7NuE1ZoGf6RiCa"
    }
  ]
}'

Python

python
import reuseforge

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

result = client.post_ledger_events(
    events=[
            {
                "id": "3c6e1f0b9a7d42885e1c0a9f3b2d4e6a8c0b1d3f5a7c9e2b4d6f8a0c1e3b5d79",
                "body": {
                    "kind": "block.publish",
                    "author": "rb1Qm3pX0vN8cT2yJ4kL6hD9sA1fG5wE7uB3iZ0oR2tY",
                    "data": {
                        "name": "Invoice extractor",
                        "kind": "skill",
                        "summary": "Extracts vendor totals and line items from PDF invoices.",
                        "url": "https://github.com/acme/invoice-extractor",
                        "capabilities": ["document-parsing"],
                        "license": "MIT",
                        "price_usd": 0,
                        "version": "1.4.0",
                    },
                    "lamport": 1042,
                    "parents": ["8a1d0c7e5b3f9a2d4c6e8b0a1d3f5c7e9b2a4d6f8c0e1a3b5d7f9c2e4a6b8d01"],
                    "ts": 1793700000,
                },
                "sig": "4Z8mQeV1xJr0Sk9TnC3bHdW5yLfA7uPoGi2EtRaN6vXcM1sKjDq8YhBlOw0UzFg3ItPe5CnSvHrA9dJk2LmQxT4bWy7NuE1ZoGf6RiCa",
            },
        ],
)
print(result)

JavaScript

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

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

const result = await client.postLedgerEvents({
  events: [
    {
      id: "3c6e1f0b9a7d42885e1c0a9f3b2d4e6a8c0b1d3f5a7c9e2b4d6f8a0c1e3b5d79",
      body: {
        kind: "block.publish",
        author: "rb1Qm3pX0vN8cT2yJ4kL6hD9sA1fG5wE7uB3iZ0oR2tY",
        data: {
          name: "Invoice extractor",
          kind: "skill",
          summary: "Extracts vendor totals and line items from PDF invoices.",
          url: "https://github.com/acme/invoice-extractor",
          capabilities: ["document-parsing"],
          license: "MIT",
          price_usd: 0,
          version: "1.4.0",
        },
        lamport: 1042,
        parents: ["8a1d0c7e5b3f9a2d4c6e8b0a1d3f5c7e9b2a4d6f8c0e1a3b5d7f9c2e4a6b8d01"],
        ts: 1793700000,
      },
      sig: "4Z8mQeV1xJr0Sk9TnC3bHdW5yLfA7uPoGi2EtRaN6vXcM1sKjDq8YhBlOw0UzFg3ItPe5CnSvHrA9dJk2LmQxT4bWy7NuE1ZoGf6RiCa",
    },
  ],
});
console.log(result);

CLI

bash
rf ledger push

# rf ledger push [file]
# all options: rf ledger push --help

Response 200 OK:

json
{
  "added": 1,
  "duplicates": 0,
  "rejected": [
    {
      "id": "0b7a2f4c6e8d1a3b5c7d9e0f2a4b6c8d1e3f5a7b9c0d2e4f6a8b1c3d5e7f9a0b",
      "code": "invalid_signature",
      "message": "Signature does not match the author key."
    }
  ]
}