Developers · API reference

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.

✦ Authentication

Bearer tokens, versioned headers, idempotent by default.

  • Base URLhttps://api.stellus.com/v1
  • Auth headerAuthorization: Bearer sk_live_...
  • Version pinStellus-Version: 2026-06-01
  • IdempotencyIdempotency-Key: <opaque uuid>
authenticated request
curl200 OK
curl https://api.stellus.com/v1/identities \
  -H "Authorization: Bearer sk_live_..." \
  -H "Stellus-Version: 2026-06-01" \
  -H "Idempotency-Key: 5a2f-7d14-c891"
✦ Resources

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.

POST/v1/identitiesCreate and verify a party through OzID.
GET/v1/identities/:idRetrieve an identity and its verification state.
POST/v1/tokens/mintMint ozUSD against reserves or OZD against deposits.
POST/v1/tokens/redeemBurn tokens and disburse to a linked funding source.
POST/v1/tokens/convertConvert between ozUSD and OZD via OzID.
POST/v1/transfersMove value between verified parties.
POST/v1/transfers/batchSubmit up to 25,000 transfer intents in one call.
POST/v1/settlementsReconcile and net across counterparties.
POST/v1/payoutsInitiate last-mile disbursement across our partner rails.
GET/v1/webhooksList active webhook subscriptions.
POST/v1/webhooksSubscribe an endpoint to lifecycle events.
DELETE/v1/webhooks/:idUnsubscribe a webhook endpoint.
✦ Example · Transfers

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.

POST /v1/transfers
curlRequest
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
response
json200 OK · 0.42s
{
  "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
}
✦ Errors

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-After header.
error response
json422 Unprocessable
{
  "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"
  }
}
✦ Webhooks

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.

app/webhooks/stellus/route.ts
typescriptNext.js route
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");
}
Event types
  • identity.verified
  • identity.rejected
  • transfer.created
  • transfer.settled
  • transfer.review
  • transfer.failed
  • redemption.completed
  • payout.delivered
  • webhook.rotated

Conventions worth knowing

Idempotency

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.

Pagination

Cursor-based via ?cursor and ?limit (max 200). Responses include next_cursor when more results exist. No offset pagination.

Rate limits

Per-account limits tuned to your plan. 429s carry a Retry-After header. Batch endpoints count as one request.

Versioning

Version pins per header, not URL. Fields are added; never removed silently. Breaking changes ship as a new version string.

Request access to the sandbox.
Talk to us