On this page

API

Quickstart

Get a token, search, plan, install and buy on ReuseForge in curl, Python, JavaScript and the rf CLI, with every step runnable against reuseforge.com or your own node.

This walks the whole loop once: a token, a search, a plan for a goal and a budget, an install, and a purchase. Reads and plans work without a token. Every snippet has four forms; pick one and the choice sticks across the site.

Sample data. The examples use acme/invoice-extractor, a sample item from the contract's own examples. Replace it with an owner/slug from your own search results. Money is always integer US cents in the API (budget_cents: 5000 is $50.00); the CLI takes dollars (--budget 50).

1. Install the tooling

You need none of it for curl. The SDKs and the CLI are not on PyPI or npm yet, so install them from a checkout of the repository:

Python

bash
git clone https://github.com/Longfordjames/Claude-1 && cd Claude-1
pip install ./sdk/python            # Python 3.9+, standard library only
python3 -c "import reuseforge; print(reuseforge.__version__)"

JavaScript

bash
git clone https://github.com/Longfordjames/Claude-1 && cd Claude-1
npm install ./sdk/js                # Node 18+; ESM; also runs on Workers, Deno, Bun and browsers

CLI

bash
git clone https://github.com/Longfordjames/Claude-1 && cd Claude-1
npm install -g ./cli                # Node 18+; installs rf and reuseforge
rf --version

2. Get a token

Anonymous calls can search, read items and plan, at lower rate limits. Everything that changes something needs a token.

  1. Sign in to the web app and open Settings, API tokens (/app/).
  2. Name the token and choose scopes. For this guide Read is enough for steps 3 to 6, and Orders adds the buying step.
  3. Copy the token. It starts with rf_ and is shown once; store it like a password.
bash
export REUSEFORGE_TOKEN=rf_...      # the SDKs and the CLI read this variable

The web app issues the legacy scope names read, write, orders (and admin for administrators), which expand to the fine-grained scopes described in authentication. A token with the orders scope can spend, so it gets a default lifetime cap of $50 that you can see in whoami. For an agent, make a narrower token with the create_token operation; see agent spending limits.

Never put a token in client-side code, a repository or a prompt. A token acts as you within its scopes. Revoke it in Settings if it leaks.

3. Check who you are

get_me returns your account, the scopes the token holds and its spend limit.

curl

bash
curl https://reuseforge.com/api/v1/me \
  -H "Authorization: Bearer $REUSEFORGE_TOKEN"

Python

python
import reuseforge

client = reuseforge.Client()          # token from REUSEFORGE_TOKEN, or the file `rf login` wrote
me = client.get_me()
print(me["handle"], me["auth"]["scopes"], me["auth"]["spend_limit_cents"])

JavaScript

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

const client = new ReuseForge();      // token from REUSEFORGE_TOKEN, or the file `rf login` wrote
const me = await client.getMe();
console.log(me.handle, me.auth.scopes, me.auth.spend_limit_cents);

CLI

bash
rf login            # paste the token once; or: echo "$REUSEFORGE_TOKEN" | rf login --with-token
rf whoami

401 invalid_token means the token is wrong or revoked, 401 token_expired that it ran out (new tokens last 90 days by default). See errors.

search_items filters public, active items. Add a token to also see your own private ones.

curl

bash
curl -G https://reuseforge.com/api/v1/items \
  --data-urlencode 'q=invoice pdf extraction' \
  --data-urlencode 'kind=skill,harness' \
  --data-urlencode 'max_price_cents=2000' \
  --data-urlencode 'limit=5'

Python

python
import reuseforge

client = reuseforge.Client()
for item in client.search_items(q="invoice pdf extraction", kind=["skill", "harness"], max_price_cents=2000, limit=5, max_items=5):
    print(item["full_name"], item["kind"], reuseforge.dollars(item["price_cents"]))

JavaScript

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

const client = new ReuseForge();
for await (const item of client.searchItems({ q: 'invoice pdf extraction', kind: ['skill', 'harness'], max_price_cents: 2000, limit: 5, maxItems: 5 })) {
  console.log(item.full_name, item.kind, dollars(item.price_cents));
}

CLI

bash
rf search 'invoice pdf extraction' --kind skill --kind harness --max-price 20 --limit 5

Results are a page: {data, next_cursor, has_more}. The SDKs iterate across pages for you.

5. Plan

Give plan_goal a goal and a budget. It decomposes the goal into capabilities, finds candidates in the registry (and, with online, on GitHub, npm, PyPI and other sources) and returns the Pareto-optimal options: higher quality, lower cost, lower risk. Nothing is bought. A plan can be fetched for 24 hours (expires_at).

curl

bash
curl -X POST https://reuseforge.com/api/v1/plans \
  -H "Content-Type: application/json" \
  -d '{"goal": "RAG chatbot over my PDF invoices", "budget_cents": 5000, "online": true}'

Python

python
import reuseforge

client = reuseforge.Client()
plan = client.plan_goal(goal="RAG chatbot over my PDF invoices", budget_cents=5000, online=True)
best = plan["recommended"]
print(plan["id"], "options:", len(plan["pareto_front"]))
print("to buy:", reuseforge.dollars(best["paid_total_cents"]), "to build:", reuseforge.dollars(best["build_total_cents"]))
for step in best["steps"]:
    print(step["requirement"], "->", step["action"], step["candidate"]["item"] if step.get("candidate") else "")

JavaScript

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

const client = new ReuseForge();
const plan = await client.planGoal({ goal: 'RAG chatbot over my PDF invoices', budget_cents: 5000, online: true });
const best = plan.recommended;
console.log(plan.id, 'options:', plan.pareto_front.length);
console.log('to buy:', dollars(best.paid_total_cents), 'to build:', dollars(best.build_total_cents));
for (const step of best.steps) console.log(step.requirement, '->', step.action, step.candidate?.item ?? '');

CLI

bash
rf plan 'RAG chatbot over my PDF invoices' --budget 50 --online --out plan.json

Each step of an option says what to do for one requirement: use an existing item, buy a paid one, or build it yourself (see build_brief for a ready-made brief). plan_goal is rate limited more tightly than other reads: 5 a minute for anonymous callers and 20 a minute with a token (see rate limits). Read the explanations and sources members before you trust a result; sources says which connectors answered.

6. Install

Installing resolves the install descriptor, downloads the bundle, verifies every file hash before writing anything, and records the result in reuseforge.lock. It never pays and never runs anything the package suggests.

curl

bash
# The descriptor says which files go where for a target; the bundle holds the file contents.
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/install?target=claude-code'
curl 'https://reuseforge.com/api/v1/items/acme/invoice-extractor/versions/latest/bundle'

Python

python
import reuseforge

client = reuseforge.Client()
result = client.install("acme/invoice-extractor", target="claude-code", dest=".")
print(result["version"], [f["path"] for f in result["files"]])

JavaScript

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

const client = new ReuseForge();
const result = await install(client, 'acme/invoice-extractor', { target: 'claude-code', dest: process.cwd() });
console.log(result.version, result.files.map((f) => `${f.status} ${f.path}`));

CLI

bash
rf install acme/invoice-extractor --target claude-code
rf list           # what is installed
rf verify         # re-hash installed files against reuseforge.lock, offline

A paid item you do not own stops with 402 payment_required. The error carries an order_hint: the exact create_order request that buys it. The CLI prints it and exits with code 7; the SDKs raise PaymentRequiredError. Install targets are generic, claude-code, cursor, codex and mcp-json; see install descriptors for where each kind goes.

7. Buy

Paid items are bought through an order: the buyer pays into escrow, the item is delivered, and the buyer accepts (or disputes) to release the money. Payments run in test mode on a simulated rail, so no real money moves. create_order and pay_order require an Idempotency-Key; the SDKs and the CLI generate one for you and reuse it across retries.

Availability. The orders operations are in the contract and implemented by the self-hosted node, but they are not switched on at reuseforge.com yet: there they answer 501 not_implemented. Run the buying steps against your own node (see self-hosting) or wait for the hosted payments group. The availability table is generated from the source and shows the current state.

curl

bash
API=https://reuseforge.com/api/v1     # or your node: http://127.0.0.1:8420/api/v1
AUTH="Authorization: Bearer $REUSEFORGE_TOKEN"

# 1. quote an order for the paid items of a plan
curl -X POST $API/orders -H "$AUTH" -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"plan_id": "pln_goalinvoice2", "rail": "simulated"}'

# 2. pay it into escrow (simulated rail: no body needed)
curl -X POST $API/orders/ord_tqjv5mw3k2na/pay -H "$AUTH" -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" -d '{}'

# 3. read it: items hosted on ReuseForge are delivered automatically once the order is funded
curl $API/orders/ord_tqjv5mw3k2na -H "$AUTH"

Python

python
import reuseforge

client = reuseforge.Client()
plan = client.plan_goal(goal="RAG chatbot over my PDF invoices", budget_cents=5000)
order = client.create_order(plan_id=plan["id"], rail="simulated")          # state: awaiting_payment
print("total", reuseforge.dollars(order["total_cents"]), "fee", reuseforge.dollars(order["fee_cents"]))

order = client.pay_order(order["id"])                                      # state: funded
order = client.wait_for_order(order["id"], states=("funded", "settled"))
client.install("acme/invoice-extractor", target="claude-code", dest=".")   # access starts at delivery, before release

JavaScript

javascript
import { ReuseForge, dollars, install } from '@reuseforge/sdk/node';

const client = new ReuseForge();
const plan = await client.planGoal({ goal: 'RAG chatbot over my PDF invoices', budget_cents: 5000 });
let order = await client.createOrder({ plan_id: plan.id, rail: 'simulated' });        // state: awaiting_payment
console.log('total', dollars(order.total_cents), 'fee', dollars(order.fee_cents));

order = await client.payOrder(order.id);                                              // state: funded
order = await client.waitForOrder(order.id, { states: ['funded', 'settled'] });
await install(client, 'acme/invoice-extractor', { target: 'claude-code', dest: process.cwd() });

CLI

bash
rf orders create --plan pln_goalinvoice2 --rail simulated
rf orders pay ord_tqjv5mw3k2na                       # shows the summary and asks "Proceed? [y/N]"
rf orders pay ord_tqjv5mw3k2na --yes --max-spend 15  # no terminal: --yes alone never pays, it needs a ceiling too
rf install acme/invoice-extractor --buy              # the same in one command

The last step, accepting, releases the escrow to the seller and cannot be undone. It needs the orders:accept scope and the body flag confirm: true, and only a signed-in person can grant that scope to a token. An autonomous agent can buy, but it cannot declare itself satisfied. If you do nothing, the acceptance window (7 days by default) ends and the money is released anyway; if something is wrong, dispute_order freezes the escrow and needs only orders:create.

curl

bash
curl -X POST $API/orders/ord_tqjv5mw3k2na/accept -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"confirm": true, "note": "Tested against 400 invoices."}'

Python

python
order = client.accept_order(order["id"], confirm=True, note="Tested against 400 invoices.")   # needs orders:accept

JavaScript

javascript
order = await client.acceptOrder(order.id, { confirm: true, note: 'Tested against 400 invoices.' });   // needs orders:accept

CLI

bash
rf orders accept ord_tqjv5mw3k2na        # on a terminal: type the order id to confirm
rf orders accept ord_tqjv5mw3k2na --yes --confirm ord_tqjv5mw3k2na   # without a terminal

Money rules the CLI adds on top of the API are listed in the CLI reference.

Where next

Last updated: