Saxeo Vault
Saxeo Vault is a private registry for tokenized real-world assets. The principle is tokenize privately, settle publicly: everything sensitive is sealed before it touches storage, every state change is hash-chained, and batch commitments anchor to Solana, so a public observer can verify that history is intact without learning what it contains.
What is private, what is public
| Surface | Visibility |
|---|---|
| Declared value, yield, maturity, notes | VisibilitySealed (AES-256-GCM), issuer's session only |
| Position sizes | VisibilitySealed, each holder sees only their own |
| Transfer amounts and counterparties | VisibilitySealed, the two parties only |
| Asset name and type | VisibilityVisible to holders of the asset |
| Event commitments and chain hashes | VisibilityPublic: GET /v1/vault/chain/{id} |
| Batch anchor roots + Solana signatures | VisibilityPublic: GET /v1/vault/anchors/{id} |
The database stores sha256 commitments of the sealed content, so a leaked dump reveals structure, never values. Supporting documents are never uploaded at all: the browser hashes them locally and only the digest is registered.
The ledger
Every asset carries an append-only event chain:
hash(n) = sha256( hash(n-1) ‖ commitment(n) )
Rewriting any event breaks every later hash. The chain is public: anyone holding an asset id can fetch it and recompute every link, no Saxeo account required.
Settlement
The anchor worker batches unanchored event hashes, computes a batch root, and
publishes sable-vault:v1:<root> to Solana mainnet as a memo transaction.
GET /v1/vault/anchors/{id} returns the root, the ordered event hashes, and
the Solana signature, so the root is recomputable and the on-chain memo
checkable by anyone. Events not yet covered by a finalized anchor are
labeled awaiting anchor: the registry never fabricates settlement.
Distributions: paying holders
Real assets pay: interest, dividends, a principal return. A distribution records a payout the issuer made across current holders, split pro-rata by position. It is not a transfer. It does not move principal; it records that a total was paid and seals each holder's share.
POST /v1/vault/assets/{id}/distribute { total_usd, kind, note? }
kind is one of yield, interest, dividend, principal, other. The
total is split pro-rata across holders by current position, floored per holder
with the rounding remainder handed to the largest holder, so the shares sum to
the declared total to the micro-dollar. Each share is sealed at rest; the payout
appends one hash-chained yield_distribution event, so it anchors to Solana
with everything else. The issuer sees the total; each holder sees only their own
share (GET /v1/vault/distributions). A distribution fires an amount-free
vault_distribution webhook.
Third-party attesters
An issuer can name someone else — an auditor, a custodian, an appraiser, counsel — as an attester on one asset, and that party can then record statements against it.
POST /v1/vault/assets/{id}/attesters { wallet, role, label?, expires_in_days? }
GET /v1/vault/assets/{id}/attesters
DELETE /v1/vault/assets/{id}/attesters/{attester_id}
POST /v1/vault/assets/{id}/attestations { kind, statement, role?, document_sha256?, attester_signature? }
GET /v1/vault/assets/{id}/attestations
role is one of auditor, custodian, appraiser, legal, other. The
wallet must already have a Saxeo account (one SIWE sign-in), because a role is a
permission on an account. Granting a role is not a statement of fact and
Saxeo checks no credentials: the issuer is saying who they have engaged.
An attestation seals its statement at rest, chains an attestation event onto
the asset ledger, and carries two signatures, which the API and the UI
never blur together:
| Label | What it proves |
|---|---|
gateway-signed record of who attested | What it provesSaxeo's registry signer over the canonical record: this account, holding this issuer-granted role, recorded this statement hash at this time. |
gateway-signed + attester-wallet-signed | What it provesThe above, plus the attester's own wallet signed the same message — so the statement is provably theirs, not merely something we recorded. |
Neither signature says the statement is true. Saxeo does not audit, appraise, or custody anything.
The attester signs this exact string (rebuildable by anyone holding the same facts, which is what makes the signature checkable off-platform):
sable-vault-attestation:v1:{asset_id}:{attester_account}:{role}:{kind}:{statement_sha256}:{document_sha256 or -}
A signature that recovers to a wallet not linked to the attester's account
is refused, not stored unverified. The gateway-signed record verifies
through the same public POST /v1/receipts/verify as every other Saxeo
artifact. Issuers, holders, and active attesters can read an asset's
attestations; a regulator can too, through a view key
carrying the attestations scope. Revoking a role stops future attestations —
ones already recorded stand, because a ledger that can retract history is not a
ledger. A new attestation fires an amount-free vault_attestation
webhook.
Claim links: sending to a wallet with no account
A transfer used to require the recipient to have signed in first. Now it does not: transferring to a wallet with no Saxeo account parks the position as a claim bound to that wallet.
The value leaves the sender immediately (chain event transfer_pending_claim)
and the response carries a one-time claim URL — shown once, stored only as a
sha256 — of the form https://www.saxeonetwork.tech/vault/claim/{token}. The claim
settles (chain event claim_settled) when the recipient signs in with that
wallet, whether they open the link or simply sign in: the SIWE signature is the
proof the claim was waiting for. The books balance at every step — sender minus
the amount, the claim holding it, then the recipient plus it.
GET /v1/vault/claims (session) claims you sent, with amounts
POST /v1/vault/claims/{id}/cancel (session) refund an unclaimed one
GET /v1/vault/claims/{token} (public) asset name + bound wallet only
POST /v1/vault/claim/{token} (session) settle it into your account
The public view is deliberately thin: the asset name and the wallet the claim is
bound to, never the amount and never the sender. A claim that is missing,
settled, cancelled, or expired answers the same "not available", so probing
tokens reveals nothing. Unclaimed claims expire after 30 days and refund to the
sender automatically (chain event claim_refunded); the sender can also cancel
one at any time. A claim is bound to one wallet — signing in with a different
one is refused, never silently redirected.
Sealed document custody
By default the registry stores document digests only: the browser hashes a file locally and the sha256 is registered. That default stands. An issuer who wants Saxeo to actually hold the deed or the audit letter can now store it:
POST /v1/vault/assets/{id}/documents { name, content_type, content_b64, holder_visible? }
GET /v1/vault/assets/{id}/documents
GET /v1/vault/assets/{id}/documents/{doc_id}
DELETE /v1/vault/assets/{id}/documents/{doc_id}
GET /v1/vault/view/{token}/documents/{doc_id} (view key, `documents` scope)
Content is AES-256-GCM-sealed at rest, opened in-frame only to answer an
authorized read, and never logged — the same posture as
Relay objects. The sha256 is chained (document_added), so what
was held is part of the tamper-evident record. Up to 10 MB per document, and
per-asset in total by operator configuration (100 MB default); PDF, text,
markdown, csv, json, images, Word and Excel — nothing executable, no HTML.
Visibility is issuer-only unless the issuer marks a document holder_visible.
Removing one destroys the ciphertext immediately and chains document_removed
— the hash stays in the chain, because history that can be quietly deleted
is not a ledger.
Note the honest difference from digests: a digest never leaves your device, and a stored document does. Storing is a deliberate choice, disclosed at the point of upload.
Proofs: verify without revealing
An owner mints a signed statement disclosing exactly the fields they choose
(POST /v1/vault/proofs). The statement carries the chain head, the latest
anchor, and the disclosed values, signed secp256k1/EIP-191 by the same signer
as receipts, and verifies through the same public
endpoint:
curl https://www.saxeonetwork.tech/__api/v1/receipts/verify \
-H 'content-type: application/json' \
-d '{"receipt": "<proof>", "signature": "<signature>"}'The trust model, honestly
Every proof embeds its own trust framing: attested (signed by the Saxeo registry over its hash-chained ledger) plus a public anchor when one exists. This is not zero-knowledge cryptography, and we don't call it that. What a verifier gets: the registry's signature is genuine, the ledger it signed over is tamper-evident, and its anchors exist on a public chain. What a verifier is trusting: that Saxeo's registry recorded honestly. Asset entries are issuer-declared. The registry records what an issuer states and proves the record's integrity; it does not appraise assets or verify backing.
What Saxeo Vault is not
Registry infrastructure only: Saxeo does not custody assets, make investment offers, or provide legal enforcement of ownership. Those wrappers belong to issuers and their counsel.
Endpoints
| Method | Path | Auth |
|---|---|---|
| POST / GET | Path/v1/vault/assets | Authsession |
| GET | Path/v1/vault/assets/{id} | Authsession |
| GET | Path/v1/vault/portfolio | Authsession |
| GET | Path/v1/vault/assets/{id}/holders | Authsession, issuer only (the cap table) |
| POST | Path/v1/vault/assets/{id}/close | Authsession, issuer only, irreversible |
| POST | Path/v1/vault/assets/{id}/distribute | Authsession, issuer only (pay holders) |
| POST / GET | Path/v1/vault/transfers | Authsession |
| GET | Path/v1/vault/distributions | Authsession (your payouts, as issuer or holder) |
| POST | Path/v1/vault/proofs | Authsession |
| POST / GET | Path/v1/vault/assets/{id}/attesters | Authsession, issuer only (grant / roster) |
| DELETE | Path/v1/vault/assets/{id}/attesters/{attester_id} | Authsession, issuer only |
| POST / GET | Path/v1/vault/assets/{id}/attestations | Authsession (record: role-holders; read: issuer, holders, attesters) |
| POST / GET | Path/v1/vault/assets/{id}/documents | Authsession (store: issuer only; list: per visibility) |
| GET / DELETE | Path/v1/vault/assets/{id}/documents/{doc_id} | Authsession (read: authorized; delete: issuer only) |
| GET | Path/v1/vault/claims | Authsession (claims you sent) |
| POST | Path/v1/vault/claims/{id}/cancel | Authsession, sender only |
| POST | Path/v1/vault/claim/{token} | Authsession (settle into your account) |
| GET | Path/v1/vault/claims/{token} | Authpublic (asset name + bound wallet only) |
| GET | Path/v1/vault/chain/{id} | Authpublic |
| GET | Path/v1/vault/anchors/{id} | Authpublic |
| GET | Path/v1/vault/view/{token}/documents/{doc_id} | Authpublic (view key, documents scope) |
An issuer sees the full holder register (/holders); each holder sees only
their own position. Closing an asset chains an asset_closed event and stops
transfers permanently, irreversible by design, so recorded history can never
quietly change meaning. Transfers fire amount-free
vault_transfer_sent / vault_transfer_received webhooks.
Transfers settle straight into the recipient's Saxeo account. If that wallet has no account yet, the position is held as a claim link and settles the moment they sign in — see above — so a position is never unclaimable and never stranded.