The Stellus API.
A clean, REST-style API for minting, redeeming, converting, and settling regulated dollars. Idempotent by default, versioned by header, streamed by webhook.
Bearer tokens, versioned headers, idempotent by default.
- Base URL
https://api.stellus.com/v1 - Auth header
Authorization: Bearer sk_live_... - Version pin
Stellus-Version: 2026-06-01 - Idempotency
Idempotency-Key: <opaque uuid>
curl https://api.stellus.com/v1/identities \
-H "Authorization: Bearer sk_live_..." \
-H "Stellus-Version: 2026-06-01" \
-H "Idempotency-Key: 5a2f-7d14-c891"Six resources cover the money lifecycle.
Each resource ships with a consistent shape: list, retrieve, create where applicable, and (for transfers and payouts) a batch endpoint.
Create a transfer end to end.
One call submits the intent. Stellus verifies both parties through OzID, screens the transfer against your policy (sanctions, risk, velocity, quorum), routes to the right rail, and returns a settled record — or a policy denial you can act on.
curl https://api.stellus.com/v1/transfers \
-H "Authorization: Bearer sk_live_..." \
-H "Stellus-Version: 2026-06-01" \
-H "Idempotency-Key: 5a2f-7d14-c891" \
-d asset=ozUSD \
-d amount=50000.00 \
-d from=acct_meridian_treasury \
-d to=acct_pareto_settlement \
-d network=base{
"id": "tx_01HXQ2P7A1V0",
"object": "transfer",
"status": "settled",
"asset": "ozUSD",
"amount": "50000.00",
"network": "base",
"from": "acct_meridian_treasury",
"to": "acct_pareto_settlement",
"policy": {
"risk_score": 2,
"sanctions": "clear",
"travel_rule": "attached"
},
"settled_at": "2026-06-29T18:14:07Z",
"finality_ms": 420
}Predictable failure modes.
Every error carries a stable type, a specific code, a human-readable message, and (where applicable) the policy that caused the denial. Errors are safe to switch on.
- policy_denied — compliance policy blocked the transfer inline.
- insufficient_funds — source account cannot cover the amount and fees.
- counterparty_unverified — recipient identity has not cleared OzID.
- idempotency_conflict — reusing an idempotency key with a different payload.
- rate_limited — slow down; see the
Retry-Afterheader.
{
"error": {
"type": "policy_denied",
"code": "recipient_risk_score_exceeded",
"message": "Recipient risk score 6 exceeds policy limit of 3.",
"policy": "treasury-default",
"request_id": "req_01HXQ2P7A1V0"
}
}Signed, replay-safe events.
Every webhook carries a Stellus-Signature header signed with your endpoint secret. The SDKs ship a verifier; the raw scheme is HMAC-SHA256 over the request body plus a per-event nonce that expires in 5 minutes.
import { verifyStellusSignature } from "@stellus/sdk";
export async function POST(req: Request) {
const body = await req.text();
const sig = req.headers.get("stellus-signature");
if (!verifyStellusSignature(body, sig, process.env.STELLUS_WEBHOOK_SECRET)) {
return new Response("invalid signature", { status: 401 });
}
const event = JSON.parse(body);
switch (event.type) {
case "transfer.settled": await onSettled(event.data); break;
case "transfer.review": await onReview(event.data); break;
case "redemption.completed": await onRedeemed(event.data); break;
}
return new Response("ok");
}identity.verifiedidentity.rejectedtransfer.createdtransfer.settledtransfer.reviewtransfer.failedredemption.completedpayout.deliveredwebhook.rotated
Conventions worth knowing
Provide an Idempotency-Key on every write. Retries are safe within 24 hours; the same key with a different payload returns a 409 with a clear message.
Cursor-based via ?cursor and ?limit (max 200). Responses include next_cursor when more results exist. No offset pagination.
Per-account limits tuned to your plan. 429s carry a Retry-After header. Batch endpoints count as one request.
Version pins per header, not URL. Fields are added; never removed silently. Breaking changes ship as a new version string.