@ralioco/sdk
v0.1.4
Published
Official TypeScript SDK for the Ralio agentic payment API.
Maintainers
Readme
Ralio TypeScript SDK
The official TypeScript client for the Ralio agentic payment API.
It handles the machine-authentication path end to end — OAuth 2.1
client_credentials with private_key_jwt and DPoP-bound access tokens — so
your integration can talk to an agent without hand-rolling JWT signing, proof
generation, or token refresh.
Scope. This SDK targets autonomous integrations such as agent hosts, backend services, and other server-side automation. It authenticates as a credential binding, which can hold the
agents:executeandtransactions:readscopes. Agent and binding management (agents:config) is a human-only operation in the console and is intentionally not part of this SDK.
Installation
npm install @ralioco/sdkRequires Node.js 20.19+, 22.13+, or 24+ (matches our toolchain's
engines.node floor). The SDK is ESM-first and ships CommonJS too; types are
bundled.
Authentication model
Ralio's machine path has no shared client secret. Each credential is a P-256 private key controlled by your integration:
- The owner mints a one-time registration ticket in the console
(Settings → Credentials → New credential), choosing the target agent and
a scope ceiling. That is where consent happens. They send you the
ralio-reg-…ticket. - You call
register()once on the agent host. It generates a keypair locally and submits the public key with the ticket; the binding is active as soon as the server responds — no approval step, no polling. The owner gets an email receipt with a revoke link. The credentials are persisted to the local Ralio credential store. - From then on,
RalioClientmints and refreshes DPoP-bound access tokens transparently and signs a fresh proof for every request.
See the API authentication guide for the protocol details.
Quickstart
With the owner's ticket in RALIO_REGISTRATION_TICKET, onboarding is two
calls:
import { register, RalioClient } from "@ralioco/sdk";
await register(); // run once; the binding is active when this returns
const client = new RalioClient(); // zero-config: reads the persisted credentials
const reply = await client.chat.send({ message: "What is my current balance?" });register() activates the binding in a single call (or rejects with a
RalioRegistrationError if the ticket is invalid, expired, or already
consumed). The private key is generated locally, written to
~/.ralio/keys/<jkt>.pem, and never leaves the host.
Everything is overridable when you want to manage credentials yourself:
import { register } from "@ralioco/sdk";
const binding = await register({
ticket: "ralio-reg-...", // instead of RALIO_REGISTRATION_TICKET
privateKeyPath: "ralio-key.pem", // generated and written here
requestedScopes: ["agents:execute", "transactions:read"],
});
console.log(binding.clientId); // cb_... — store this alongside the keyUse the client
import { RalioClient } from "@ralioco/sdk";
// Zero-config: reads the credentials persisted by register().
const client = new RalioClient();
// Or manage credentials yourself:
// const client = await RalioClient.create({
// clientId: "cb_...",
// privateKeyPath: "ralio-key.pem",
// });
// One-shot chat — uses the agent attached to the active credential.
const reply = await client.chat.send({
message: "What is my current balance?",
});
console.log(reply.reply);
// Streaming chat (server-sent events)
for await (const event of client.chat.stream({
message: "List my recent payments",
})) {
if (event.event === "text_delta") {
process.stdout.write(event.text);
} else if (event.event === "tool_started") {
console.log(`\n[tool] ${event.data.tool_name}`);
}
}
// Transactions — list endpoints are paginated.
const page = await client.transactions.list({ perPage: 20 });
console.log(`showing ${page.data.length} of ${page.total} transactions`);
for (const txn of page.data) {
console.log(txn.date, txn.amount, txn.currency, txn.creditor, txn.status);
}
// Payment intents — what the agent proposed, with per-leg execution detail.
const intents = await client.paymentIntents.list({ perPage: 20 });
for (const intent of intents.data) {
console.log(intent.createdAt, intent.totalAmount, intent.currency, intent.approvalStatus);
}RalioClient also implements Symbol.dispose, so under using it is released
automatically:
using client = new RalioClient();Credentials load lazily on the first request; use await RalioClient.create()
instead of new RalioClient() to load them eagerly and fail fast.
The active credential determines which agent receives chat requests. To use a different agent, authenticate or register a new credential for that agent.
For custom credential stores and clustered deployments, see Credential stores.
Environment variables
| Variable | Meaning |
| --------------------------- | ---------------------------------------------- |
| RALIO_REGISTRATION_TICKET | Default ticket for register() |
| RALIO_API_URL | API origin (default https://api.ralio.co) |
| RALIO_CONFIG_DIR | Credential store location (default ~/.ralio) |
Payments
There is no payments.create() method by design. Payments are executed by the
agent, not by direct REST calls: drive the agent with chat.send /
chat.stream ("Pay £500 to Bob for the April invoice") and it will create the
payment, subject to its spend limits and approval rules. Use
transactions.list (executed payments) and paymentIntents.list (what the
agent proposed, with per-leg status) to read what the agent did.
Errors
All errors subclass RalioError:
| Class | When |
| ---------------------------- | --------------------------------------------------------------- |
| RalioAuthError (401) | Missing/invalid token, failed assertion, or rejected DPoP proof |
| RalioPermissionError (403) | Token lacks the required scope, or resource not owned |
| RalioNotFoundError (404) | Resource doesn't exist |
| RalioValidationError (422) | Invalid field values or business-rule violation |
| RalioRateLimitError (429) | Rate limited — back off and retry |
| RalioAPIError | Any other HTTP error (carries statusCode, detail) |
| RalioRegistrationError | Registration failed (invalid / expired / consumed ticket) |
| RalioConfigError | Local configuration problem |
import { RalioPermissionError } from "@ralioco/sdk";
try {
await client.chat.send({ message: "..." });
} catch (err) {
if (err instanceof RalioPermissionError) {
console.error("scope problem:", err.detail);
} else {
throw err;
}
}Development
npm install
npm run lint
npm run typecheck
npm test
npm run buildLicense
MIT — see LICENSE.
