Mandate Binding
Asqav lets an organization register a Mandate that authorizes one of its agents to take a set of action types within a time window. When the agent signs an action under that mandate, Asqav re-verifies the issuer signature at sign time, checks the scope and the server-clock window, runs a fail-closed revocation read, and stamps a signed authorized_under_mandate attestation onto the receipt. The attestation records that the org account that owns the signing key asserted, under its own key, a mandate covering this action.
What authorized_under_mandate proves, and what it does not
authorized_under_mandate is a self-declared issuer authorization. It proves that the org account holding the signing key asserted a mandate covering this action under its own key. It is the same trust level as framework_mappings_self_declared: a loud, signed, honest declaration by the producer, not a third-party verification by Asqav.
Asqav does NOT verify that the issuer has real-world authority. The issuer id is shape-checked against LEI, EIN, and CIK formats only. Asqav verifies the cryptographic signature over the mandate, the scope, the time window, and the revocation state. It does not certify that the issuer was entitled to grant the mandate. A verifier reading verified: true reads it as "the issuer signature re-verified and the mandate covers this action", never as "Asqav vouches for the issuer's authority".
The mandate object
A Mandate is registered via POST /orgs/{org_id}/mandates and is resolvable later via GET /orgs/{org_id}/mandates/{mandate_id}. It carries:
mandate_id: aman_<token>primary key, the resolvable locator.issuer_id: the self-declared issuer, shape-checked as LEI, EIN, or CIK.subject_agent_id: the agent this mandate authorizes.scope:{action_types, valid_from, valid_until}. Thevalid_fromandvalid_untilbounds are enforced against the server clock, never a caller timestamp.issuer_signature: an ed25519 or ecdsa-p256 envelope over the JCS-canonical{mandate_id, issuer_id, subject_agent_id, scope}. Asqav re-verifies this at registration and again at every sign.
Error codes
A sign request that carries mandate_id, or that is made under an org with require_mandate on, fails closed with HTTP 403 and one of these codes when the mandate does not authorize the action:
mandate_required: a mandate is required but none was supplied.mandate_not_found: themandate_iddoes not resolve for this org.mandate_issuer_signature_invalid: the issuer signature does not verify over the JCS subject.mandate_subject_mismatch: the mandatesubject_agent_iddoes not match the signing agent.out_of_mandate: theaction_typeis not inscope.action_types.mandate_not_yet_validormandate_expired: outside thevalid_from/valid_untilwindow.mandate_revoked: the mandate has been revoked.
The signed attestation
On success the server builds authorized_under_mandate and signs it into the receipt payload. The producer never supplies this object. A caller-supplied authorized_under_mandate in the request body is dropped before the request model is built, so it can never echo into the receipt. The attestation looks like:
{
"authorized_under_mandate": {
"mandate_id": "man_test01",
"issuer_id": "549300ABCDEF12345678",
"scope_digest": "sha256:ec9694c4261f27e98b1556fa7774dd68369e79260b77a368f5af7c64a90a77ce",
"verified": true
}
}
scope_digest is sha256: followed by the 64-hex SHA-256 of the JCS-canonical mandate scope. It is verifiable by resolving the mandate: an auditor fetches the mandate via GET /orgs/{org_id}/mandates/{mandate_id}, recomputes the JCS SHA-256 of the returned scope, and compares. The digest is NOT standalone verifiable. mandate_id is the resolvable locator that makes it checkable.
The false-mandate-attestation guard
A receipt that carries authorized_under_mandate but is malformed is a false attestation, so Asqav rejects it before the receipt persists. The conformance gate fires the false_mandate_attestation_guard when the attestation is present but is not an object, is missing mandate_id or issuer_id, carries verified other than true, or carries a scope_digest outside the sha256:<64 hex> wire form. The verbatim guard message is:
false_mandate_attestation_guard: authorized_under_mandate requires verified=true and scope_digest sha256:<64 hex>
The SDK recognises the same structure client-side, so a malformed attestation surfaces as false_mandate_attestation_guard in the local verification result before the network roundtrip.
How do I sign under a mandate via the SDK?
Python SDK
import asqav
asqav.init()
agent = asqav.Agent.create("mandate-subject")
sig = agent.sign(
"api:call",
{"user": "..."},
compliance_mode=True,
mandate_id="man_test01",
)
TypeScript SDK
import { Agent } from "@asqav/sdk";
const agent = Agent.attach({ /* ... */ });
await agent.sign({
actionType: "api:call",
context: { user: "..." },
complianceMode: true,
mandateId: "man_test01",
});
curl
curl -X POST https://api.asqav.com/api/v1/agents/agt_mandate_subject/sign \
-H "X-API-Key: $ASQAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action_type": "api:call",
"compliance_mode": true,
"mandate_id": "man_test01"
}'
How does an auditor use authorized_under_mandate?
The auditor holds the Audit Pack with the signed receipts. To weigh the mandate attestation, the auditor:
- Reads
authorized_under_mandatefrom the signed payload. - Resolves the mandate via
GET /orgs/{org_id}/mandates/{mandate_id}. - Recomputes the JCS SHA-256 of the returned scope and compares it to
scope_digest. - Re-verifies the mandate issuer signature over the JCS subject, exactly as the cloud does at sign time.
- Reads
verified: trueas self-declared issuer authority, the same trust level as a self-declared framework mapping, and calibrates how much independent corroboration the issuer claim needs.