API
Tokens operations
Personal access tokens with scopes, expiry and spend limits.
Personal access tokens with scopes, expiry and spend limits. Paths are relative to https://reuseforge.com/api/v1.
| Operation | Method | Path |
|---|---|---|
| List API tokens | GET | /tokens |
| Create an API token | POST | /tokens |
| Revoke an API token | DELETE | /tokens/{token_id} |
List API tokens
GET /tokens Enabled on reuseforge.com
Active tokens of the authenticated account. Secrets are never returned after creation.
| Property | Value |
|---|---|
| Operation ID | list_tokens |
| Authentication | Bearer token holding tokens:manage |
| Rate tier | read: 60/min per IP anonymous, 600/min per token with a token |
| Python SDK | client.list_tokens(...) |
| JavaScript SDK | client.listTokens(...) |
| CLI | rf tokens list |
| MCP tool | not exposed as a tool |
| Deployments | reuseforge.com: enabled. Python node: not implemented (answers 501). |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
cursor | query | string | no | Opaque cursor from the previous page's next_cursor. |
limit | query | integer | no | Page size. Default 30. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 OK | A page of tokens. | application/json: TokenPage |
| 401 | Missing, malformed, expired or revoked credentials. | Problem. Codes: unauthorized, invalid_token, token_expired |
| 403 | Authenticated, 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 |
| 429 | Rate limit for the operation's tier exceeded. Wait Retry-After seconds. | Problem. Codes: rate_limited |
Example
curl
curl 'https://reuseforge.com/api/v1/tokens' \
-H "Authorization: Bearer $REUSEFORGE_TOKEN"Python
import reuseforge
client = reuseforge.Client() # token from REUSEFORGE_TOKEN, or the file `rf login` wrote
for entry in client.list_tokens(): # iterating fetches further pages on demand
print(entry["id"])JavaScript
import { ReuseForge } from '@reuseforge/sdk';
const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });
for await (const entry of client.listTokens()) { // iterating fetches further pages on demand
console.log(entry.id);
}CLI
rf tokens list
# rf tokens list [options]
# all options: rf tokens list --helpResponse 200 OK:
{
"data": [
{
"id": "tok_agentreader2",
"object": "token",
"name": "ci-agent",
"prefix": "rf_k3Tz9q",
"scopes": [
"items:read",
"items:publish",
"orders:create",
"orders:pay"
],
"spend_limit_cents": 5000,
"spent_cents": 1200,
"created_at": "2026-10-20T09:00:00Z",
"last_used_at": "2026-11-03T10:07:00Z",
"expires_at": "2027-01-18T09:00:00Z"
}
],
"next_cursor": null,
"has_more": false
}Create an API token
POST /tokens Enabled on reuseforge.com
Mints a personal access token. The secret (token) is returned once.
Safety rules: a token can only mint tokens whose scopes are a subset of its own and whose spend limit is not larger. orders:accept (release escrow) is never included unless listed explicitly, and an unlimited spend limit (spend_limit_cents: null) is only honoured for an interactive session. When orders:pay is requested and the limit is omitted, the default is 5000 cents.
| Property | Value |
|---|---|
| Operation ID | create_token |
| Authentication | Bearer token holding tokens:manage |
| Rate tier | write: not allowed anonymous, 120/min per token with a token |
| Idempotency | Idempotency-Key header, optional. The SDKs and the CLI send one for you. |
| Python SDK | client.create_token(...) |
| JavaScript SDK | client.createToken(...) |
| CLI | rf tokens create |
| MCP tool | not exposed as a tool |
| Deployments | reuseforge.com: enabled. Python node: not implemented (answers 501). |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Client-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 TokenCreate
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | |
scopes | array of Scope | yes | |
expires_in_days | integer | no | Default 90. A token with the admin scope defaults to 7 days and lasts at most 30; a longer request answers 422 validation_failed. |
spend_limit_cents | integer or null | no | Default 5000 when orders:pay is requested (the only scope that can commit money). Null (unlimited) is only honoured for interactive sessions. |
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 Created | The token, including its one-time secret. | application/json: TokenWithSecret |
| 400 | The request is malformed (bad JSON, unknown or mistyped parameter, invalid cursor). | Problem. Codes: invalid_request, invalid_json, invalid_parameter, invalid_cursor, idempotency_key_required |
| 401 | Missing, malformed, expired or revoked credentials. | Problem. Codes: unauthorized, invalid_token, token_expired |
| 403 | Authenticated, 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 |
| 409 | The request conflicts with current state (duplicate resource, wrong lifecycle state, idempotency conflict). | Problem. Codes: conflict, already_exists, invalid_state, idempotency_in_progress |
| 422 | The 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 |
| 429 | Rate limit for the operation's tier exceeded. Wait Retry-After seconds. | Problem. Codes: rate_limited |
Example
curl
curl -X POST 'https://reuseforge.com/api/v1/tokens' \
-H "Authorization: Bearer $REUSEFORGE_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-agent",
"scopes": [
"items:read",
"items:publish",
"orders:create",
"orders:pay"
],
"expires_in_days": 90,
"spend_limit_cents": 5000
}'Python
import reuseforge
client = reuseforge.Client() # token from REUSEFORGE_TOKEN, or the file `rf login` wrote
result = client.create_token(
name="ci-agent",
scopes=["items:read", "items:publish", "orders:create", "orders:pay"],
expires_in_days=90,
spend_limit_cents=5000,
)
print(result["id"])JavaScript
import { ReuseForge } from '@reuseforge/sdk';
const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });
const result = await client.createToken({
name: "ci-agent",
scopes: ["items:read", "items:publish", "orders:create", "orders:pay"],
expires_in_days: 90,
spend_limit_cents: 5000,
});
console.log(result.id);CLI
rf tokens create --name ci-agent --scopes items:read,items:publish,orders:create,orders:pay --spend-limit 50
# rf tokens create [options]
# all options: rf tokens create --helpResponse 201 Created:
{
"id": "tok_agentreader2",
"object": "token",
"name": "ci-agent",
"prefix": "rf_k3Tz9q",
"scopes": [
"items:read",
"items:publish",
"orders:create",
"orders:pay"
],
"spend_limit_cents": 5000,
"spent_cents": 0,
"created_at": "2026-10-20T09:00:00Z",
"last_used_at": null,
"expires_at": "2027-01-18T09:00:00Z",
"token": "rf_k3Tz9qXw1LmN8vB4cD7eF2gH5jK6pR0sTuV3yZaQb"
}Revoke an API token
DELETE /tokens/{token_id} Enabled on reuseforge.com
Revokes immediately. Idempotent: revoking an already revoked token returns 204.
| Property | Value |
|---|---|
| Operation ID | revoke_token |
| Authentication | Bearer token holding tokens:manage |
| Rate tier | write: not allowed anonymous, 120/min per token with a token |
| Python SDK | client.revoke_token(...) |
| JavaScript SDK | client.revokeToken(...) |
| CLI | rf tokens revoke |
| MCP tool | not exposed as a tool |
| Deployments | reuseforge.com: enabled. Python node: not implemented (answers 501). |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
token_id | path | string | yes |
Responses
| Status | Meaning | Body |
|---|---|---|
| 204 No Content | Revoked. | no body |
| 401 | Missing, malformed, expired or revoked credentials. | Problem. Codes: unauthorized, invalid_token, token_expired |
| 403 | Authenticated, 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 |
| 404 | No such resource, or it is private and the caller may not know it exists. | Problem. Codes: not_found |
| 429 | Rate limit for the operation's tier exceeded. Wait Retry-After seconds. | Problem. Codes: rate_limited |
Example
curl
curl -X DELETE 'https://reuseforge.com/api/v1/tokens/tok_x7q2m9k4v1b3' \
-H "Authorization: Bearer $REUSEFORGE_TOKEN"Python
import reuseforge
client = reuseforge.Client() # token from REUSEFORGE_TOKEN, or the file `rf login` wrote
client.revoke_token("tok_x7q2m9k4v1b3")JavaScript
import { ReuseForge } from '@reuseforge/sdk';
const client = new ReuseForge({ token: process.env.REUSEFORGE_TOKEN });
await client.revokeToken("tok_x7q2m9k4v1b3");CLI
rf tokens revoke tok_x7q2m9k4v1b3
# rf tokens revoke <token_id>
# all options: rf tokens revoke --helpResponse 204 No Content with an empty body.