claim) about which business object (subject). The endpoint checks the
query came from Parmana, reads the fact from its own records, and returns a signed answer. Parmana checks the answer
against the key you registered and records it as a Trusted Signal. Any source works: it only has to answer this
protocol. Parmana holds none of the system’s credentials.
Follow it literally. If your situation is not covered, stop and ask the operator.
Rules that apply to every step
- Do the steps in order. Compare each response with Expect; if it differs, follow If not and stop.
- The endpoint answers only from its own records. It never answers from anything in the query except
claimandsubject. - The endpoint answers only queries it verified. Anything else gets
401and no fact. - Two different people propose and approve every change.
Inputs you need before you start
Step 1: make the source’s signing key
Do: on the machine that will run the endpoint, make an Ed25519 key pair. The private key never leaves it.Step 2: run the endpoint
Do: runtypescript/examples/08-business-signal-source.ts in front of your system, replacing lookupInvoice with
a read from your records. Parmana’s public key is the pem field of GET {PARMANA_URL}/keys/default.
https endpoints.
Expect: the endpoint answers a GET with 405.
Step 3: propose the registration
Do: as the maker,POST {PARMANA_URL}/business-signal-sources/changes:
201 with "status": "PENDING_APPROVAL", the endpoint as Parmana stored it, and the key in canonical
SPKI PEM. Keep changeId.
If not: INVALID_BUSINESS_SIGNAL_SOURCE names the field; EXTERNAL_ENDPOINT_ADDRESS_REFUSED means the endpoint
is not https, names an address or localhost, or resolves to an address that is not public; 409 means the name is
already registered or has a change pending. See
Propose a business signal source change.
Step 4: approve it
Do: as the second person, sign a step up authorization forchangeId and action approve, then
POST {PARMANA_URL}/business-signal-sources/changes/{changeId}/approve with { "stepUpAuthorization": … }.
Expect: 200 with "status": "APPROVED". GET /business-signal-sources lists the source as active.
If not: SAME_ACTOR_CANNOT_APPROVE_OWN_CHANGE means the maker tried to approve; EXTERNAL_ENDPOINT_ADDRESS_REFUSED
means the host’s address changed since the proposal. The change stays pending.
Step 5: declare the fact in a policy
Do: in the policy that governs the action, name the source for the fact, and take it out of anything the agent declares. Approve the policy change through policy governance.GET /policies/in-effect lists invoicePaid under signals.sourced.
Step 6: send a request
Do: have the agent send the request as usual. It need not sendinvoicePaid; if it does, the ERP’s answer must
equal it.
Expect: the decision’s assessment.businessValidation.status is VALID, and its signals hold a Trusted Signal
with source: "erp", the invoice as subject, the ERP’s value as observedValue, and
integrityProof.sourceProofVerified: true.
If not: the request is refused, with the reason in assessment.businessValidation. See the table below.
The protocol
ParmanaPOSTs to the endpoint:
signature.value is Parmana’s base64 signature over the canonical JSON of query (the SDKs’ canonicalSerialize),
with the key at GET /keys/default. Check it, check audience is your URL as registered, check expiresAt has not
passed, and answer each nonce once. signature.algorithm is the algorithm of that key: ed25519 unless the deployment
chose another (Choose a signature provider). The example accepts only ed25519.
The endpoint answers 200:
answer echoes source, nonce, signalKey, claim and subject from the query, so an answer cannot be replayed to
another question. status is observed with value and observedAt (and optionally validUntil), or not_found or
conflicting with a reason. signature.value is the base64 Ed25519 signature over the canonical JSON of answer.
What each answer does
VALID refuses the request; nothing is executed, and the Refusal Record carries the reason.
Revoke or move a source
Propose{ "action": "revoke", "name": "erp", "reason": "…" } and have a second person approve it. From then on,
policies that name erp are refused as SOURCE_UNAVAILABLE. To move the endpoint or rotate the key, revoke, then
register again. The revoked registration stays listed.
Limits
- An answer is checked when the request is decided, and its
validUntilagain at release. An external connector also receives it as a signedcondition, so its endpoint can act only if it still holds (Connect any external system). - Parmana checks the source signed the answer. It cannot check the source’s records are right: a source answers for its own data.
- See Limitations, G-92.