SDK

Integrate Ⱡ Credits into your service. Available in JavaScript and Ruby.

Download

legendum.js — JavaScript (zero dependencies, uses global fetch)

legendum.rb — Ruby (zero dependencies beyond net/http)

legendum.md — full documentation

patterns.md — integration patterns (how to combine OAuth, linking, and billing)

Configuration

Email pay@legendum.co.uk to register your service and receive your credentials. Then set environment variables or pass config directly:

LEGENDUM_API_KEY=lpk_...
LEGENDUM_SECRET=lsk_...
LEGENDUM_BASE_URL=https://legendum.co.uk

Service client

For charging credits from your backend:

// JavaScript
const legendum = require("./legendum.js");
const client = legendum.create({ apiKey, secret });

await client.charge(accountToken, 10, "API call");
await client.balance(accountToken);
const res = await client.reserve(accountToken, 50, "job");
await res.settle();  // or res.release()
await client.linkAccount("lak_...");
# Ruby
require_relative "legendum"
client = Legendum.create(api_key:, secret:)

client.charge(account_token, 10, "API call")
client.balance(account_token)
res = client.reserve(account_token, 50, "job")
res.settle  # or res.release
client.link_account("lak_...")

Service client methods

MethodDescription
charge(token, amount, desc)Charge credits from a linked account
balance(token)Get balance for a linked account
reserve(token, amount, desc)Hold credits (up to 15 min), returns reservation
request_link()Request a pairing code for account linking
poll_link(id)Poll for link confirmation
wait_for_link(id)Poll until confirmed or expired
auth_url(opts)Build a "Login with Legendum" URL
auth_and_link_url(opts)Build a "Login and link" URL (after request_link)
exchange_code(code, uri)Exchange auth code for user info
link_account(key)Link an account to your service
tab(token, desc, opts)Batch micro-charges, flush at threshold

middleware (JavaScript) / Legendum::Middleware (Ruby)

Mount server-side routes: POST …/link, POST …/auth-link (JSON body redirect_uri, state → returns { url } for login-and-link), POST …/confirm, GET …/status. Keeps API credentials on the server.

linkController (JavaScript)

For reactive UIs: legendum.linkController({ mountAt, onChange, ... }) returns startLink() (pairing popup + poll) and startAuthAndLink() with redirectUri + state. With mountAt, startAuthAndLink uses POST …/auth-link by default (no browser client). Or pass client from create() and set authLinkUrl: null to build the authorize URL in the browser after POST …/link.

Account client

For scripts and agents acting on behalf of a user:

// JavaScript
const acct = legendum.account("lak_...");
await acct.whoami();
await acct.balance();
await acct.transactions(50);
await acct.link("ABC123");
await acct.unlink("example.com");
await acct.authorize({ clientId, redirectUri, state });
# Ruby
acct = Legendum.account("lak_...")
acct.whoami
acct.balance
acct.transactions(50)
acct.link("ABC123")
acct.unlink("example.com")
acct.authorize(client_id:, redirect_uri:, state:)

Testing

// JavaScript
legendum.mock({
  charge: (token, amount, desc) => ({ email: "mock@test.com", transaction_id: 1, balance: 50 }),
});
// ... run tests ...
legendum.unmock();
# Ruby
Legendum.mock(
  charge: ->(token, amount, desc, **opts) { { "email" => "mock@test.com", "transaction_id" => 1, "balance" => 50 } }
)
# ... run tests ...
Legendum.unmock

Error handling

All methods throw/raise on failure with code, status, and message:

CodeStatusMeaning
unauthorized401Invalid API key or secret
insufficient_funds402Balance too low
bad_request400Missing or invalid fields
token_not_found404Account token not found
invalid_state409Reservation not in held state
expired410Reservation expired