@percayso-community/cayso-contracts
v3.0.0
Published
The versioned capability contract surface through which anything outside this repository reads a wallet. Published; keep it the surface of every consumer outside this tree, Piper and the Percayso Cloud, and nothing internal.
Keywords
Readme
@percayso-community/cayso-contracts
The versioned capability contract surface through which anything outside this repository reads a wallet. This is the package Piper — and any third-party integrator — depends on. Published to the public registry under Apache-2.0, even though the repository that builds it is private (CAY-0025): a possibly-public Piper cannot depend on a private package.
It exists to prevent one specific failure. Piper's own walletApi.ts redeclares
the wallet shape by hand instead of importing it, and in doing so widened a
literal 0 to number — so the one structural guarantee in that surface dies at
the HTTP boundary. The fix is a single published package whose types a consumer
imports rather than retypes.
The surface of every consumer outside this tree
Published here: the record and response types, the closed failure-reason unions,
the assertion claims and the route constants — the surface every consumer outside
this repository reads (CAY-0026, Amendment 3). Piper is the first consumer. The
Percayso Cloud is the second: its Contribution Store presents the settlement
assertion to Cayso directly, and the Cloud generates its types from the schema
entry point rather than typing Cayso's half by hand. The Cloud's two seams live in
cloud-settlement, and the settlement path, which a registered issuer calls and
no person does, is CLOUD_SETTLEMENT_ROUTE, published apart from ROUTES. The
Cloud verifies Cayso's authorisation acknowledgement under a key it reads from
ACKNOWLEDGEMENT_KEYS_ROUTE, an unauthenticated read of public keys, published
apart from both.
Percayso BizID's authority assertion (CAY-0100) is published, and from 2.0.0
it is served: an act on an Organisation Wallet needs it. AuthorityClaims is its own
type, under the identity assertion's AssertionHeader, with no verification or
assurance fields. It travels in the AUTHORITY_ASSERTION_HEADER header, beside
Authorization, and the thin client sends it only on an Organisation operation given
a per-request provider for it. Cayso binds it to the identity assertion — the same
sub, the same auth_time, its operation in the identity assertion's scope and
equal to the route's, both current at once — on provisionOrganisation,
makeCommercialPayment on the 'mandate' route, and authorisePurchase with any
onBehalfOfWalletId, which must then name the wallet the bound Organisation is bound
to, and refuses one that does not bind with a member of the closed
AuthorityBindingRefusal. The payment-allowance route and a Citizen's own purchase need
none. AssertionClaims declares auth_time, which
Percayso ID mints and the binding compares. organisationAuthority and mandateFor
are retired, authorise nothing, and are still published until the major that removes
them.
2.0.0 is a major, breaking on the wire from 1.0.0 (CAY-0101): it lists
nothing older, so GET /api/version answers 2.0.0 alone, and a consumer on 1.0.0
or on the 0.x line that negotiates through it stops reading this Cayso until it
moves to 2.0.0. See CONTRACT_VERSION's docblock for what changed.
The operator read surface, on its own entry point (CAY-0026, Amendments 4 and 5).
Four reads an operator app's server calls — the movement list, the purchase list, the
quickening ladder and the economy summary — are published at @percayso-community/cayso-contracts/operator:
their paths and scopes, query inputs (wallet id, a half-open [from, to) window, a
keyset cursor), rows and pages, and their closed refusal and not-configured bodies.
Money is Cents, a wallet is named by its wallet id, and no Percayso identity
appears on any row. It is not re-exported from the barrel, so Piper and the Cloud
never import an operator vocabulary by accident, and the schema describes it under
its own operator key rather than among the person-facing types. Cayso sends no
CORS headers: these reads are for a server, never a browser. The economy summary
(Amendment 5) answers aggregates only: whole-number counts and cent totals, with no
wallet id, identity or row of any kind. Widening the entry point beyond these four
needs a further amendment.
Deliberately not published: peer types, holdings and carves, and every operator route but those four reads. They are not a consumer's business, and putting them on the public surface widens it for nothing.
This package carries no numbers. Amounts, rates, tiers, schedules and thresholds live in the canon PRD and are read from one place. None of them are restated here.
Four entry points
| Import | What it gives you |
|---|---|
| @percayso-community/cayso-contracts | Types and constants. No runtime. |
| @percayso-community/cayso-contracts/client | The thin client — fetch, assertion header, idempotent retry. |
| @percayso-community/cayso-contracts/schema | A machine-readable descriptor of the published surface: the published, versioned surface a consumer in another language generates its types from. |
| @percayso-community/cayso-contracts/operator | The four operator reads' types and route constants, for an operator app's server. |
The split is the point: a consumer wanting only the types takes on no runtime at all. The client owns the fetch, the assertion header and the idempotent retry.
The schema entry point serves a data description of the same surface —
generated from these very types, never hand-written. It is a published, versioned
surface in its own right, and there are two ways to depend on this package through
it, by language:
- A TypeScript consumer imports the types, and the compiler holds the surface. Piper does this. For such a consumer the schema is a tool about the contract — a diff, a doc generator, a compatibility check — and never a replacement for the import.
- A consumer in another language generates from the
schemaentry point of the published tarball at a pinned version, and treats a drift between its generated types and the schema as a build failure. That is depending on the package: the pin is the lockfile entry and the regeneration is the compile. The Percayso Cloud is this consumer (CAY-0026Amendment 3;CMTY-0018§3 as amended): it is written in Go, it cannot import a TypeScript type, and its generator reads the npm tarball at a pinned version so that its Go types for the two Cloud seams incloud-settlementare never typed by hand. The package ships the schema as a JS module only, which is why the generator reads the tarball and not a registry endpoint.
What stays refused is reading the schema off the wire as a substitute for either: see the version endpoint, below.
Independent versioning
CONTRACT_VERSION is exported from the barrel and is independent — its own
semantic version, not a repo-wide constant shared with anything else. It started at
0.1.0, and from 1.0.0 it follows ordinary semantic versioning, Cayso's adoption of CMTY-0032
(CAY-0101):
a minor is additive and drops nothing, and a major is the only breaking kind. Piper's own contracts share one global version bumped across all of them
together; independent versioning across a service boundary is exactly what this
money surface gains that theirs lack (CAY-0026). The constant and the package's
version field must agree, and a test fails when they drift.
The version endpoint, and why it is not the package
A Cayso deployment serves GET /api/version, and a consumer reads it to
negotiate which contract this server speaks before speaking it. It answers four
fields: the contractVersion this deployment publishes, the
supportedContractVersions it will still honour (the negotiation set), the
schemaVersion of its database, and the build commit (the honest word
unknown when the build stamped none). The route is public — no assertion —
because you cannot negotiate the contract from behind the gate the contract
describes. The thin client's getVersion() reads it and warns once, per client
instance, when the server's contract major differs from the one the client was
built against.
A deployment keeps serving every earlier minor of its major and lists them in
supportedContractVersions, so a consumer pinned to any of them keeps working; a
consumer's handshake accepts a Cayso if contractVersion or any entry of
supportedContractVersions is on its own line: from 1.0.0 the same major, below it the
same minor. Only a
major breaks, and its first release lists nothing from an older major and says so in
the bump's changelog. An earlier major is listed only during a declared transition:
1.0.0 kept 0.32.0, 0.31.0, 0.30.0 and 0.29.0, and 2.0.0, the next major,
dropped them (CAY-0101,
amending CAY-0086).
Alongside it, GET /api/version/schema serves the same machine-readable
descriptor as @percayso-community/cayso-contracts/schema — the surface outside consumers read, with
no operator, webhook or peer route. It exists for tooling and diagnostics.
The wire is not a substitute for depending on this package. The descriptor
served here is data about this deployment; the guarantee is the published
package at a pinned version. A consumer that reads the schema off the wire and
validates or generates against it has re-created Piper's original mistake by
another route: it couples its build to a deployment's uptime, replaces a pinned
version with whatever happens to be deployed at that moment, and loses every
guarantee the moment the wire description and its code drift. Import
@percayso-community/cayso-contracts and let the compiler hold the surface, or —
in another language — generate from the schema entry point of the published
tarball at a pinned version, as the Cloud does. Read the schema endpoint when
you are building a tool about a running deployment, never to stand in for
having the package.
No dependencies
Not one — not a runtime dependency, not a peer dependency. A published contract surface that drags a tree behind it is a liability a consumer did not ask for.
Licence and the source-file header
The package is Apache-2.0 (see LICENSE) — permissive, with the
explicit patent grant, because Piper, the Companion and third-party integrators
all need to depend on it. Everything else in this repository is proprietary; do
not carry this licence beyond this package.
Every source file in this package — and only in this package — starts with the Apache boilerplate header, above the file's own docblock:
/*
* Copyright 2026 Percayso Community
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/Add it to any new file you create here, so the next person follows the convention rather than guessing it.
