Sample approval requests
Understand the signing, key-generation, and resharing payloads sent to a policy engine
The Virtual Signer sends one of three request shapes to OPA or a custom policy server. Every request is wrapped in input, and input.id identifies the io.sign operation.
These examples use synthetic, abbreviated keys. Fields can contain sensitive transaction and signer information; do not log complete production payloads without an approved retention and redaction policy.
Signing
POST <base>/sign can contain one or more items in signatures.
{
"input": {
"id": "sign-123",
"type": "sign",
"vaultId": "vault-456",
"threshold": 4,
"curves": [
{
"algorithm": "ecdsa",
"curve": "secp256k1",
"publicKey": "04abbreviated",
"xpub": "xpub-abbreviated"
}
],
"signers": [
{
"id": "signer-a",
"externalId": "risk-engine-primary",
"weight": 4,
"publicKey": "abbreviated"
}
],
"signatures": [
{
"dataToSign": ["02f1-abbreviated"],
"contentType": "application/octet-stream+hex",
"coseAlgorithm": "es256k",
"chainId": 137,
"derivationPath": "m/44'/60'/0'/0/0",
"metadata": {
"contextType": "application/evm-rlp-v1+hex",
"serializedData": "0x02f1-abbreviated",
"decoded": {
"raw": {
"ChainId": "0x89",
"To": "0x1111111111111111111111111111111111111111",
"Value": "0x3e8"
},
"parsed": {
"ChainID": "137",
"To": "0x1111111111111111111111111111111111111111",
"Amount": "1000"
}
}
}
}
]
}
}Policy usually evaluates vaultId, the signer set and threshold, contentType, coseAlgorithm, and decoded transaction metadata. Metadata is optional: if retrieval fails, the Broker can send a signing item without metadata. A safe policy rejects requests when fields it requires are absent.
Key generation
POST <base>/keygen describes the initial signer set and threshold for a new vault.
{
"input": {
"id": "keygen-123",
"type": "keygen",
"vaultId": "vault-456",
"threshold": 4,
"expiresAt": "2026-08-12T22:00:00Z",
"signers": [
{
"id": "signer-a",
"externalId": "risk-engine-primary",
"weight": 4,
"publicKey": "abbreviated"
}
]
}
}Review the proposed vault, expiry, signer identities, weights, and threshold. Do not approve an unexpected signer set merely because the Virtual Signer itself is included.
Resharing
POST <base>/reshare describes the old and proposed threshold plus every signer's membership or weight change.
{
"input": {
"id": "reshare-123",
"type": "reshare",
"vaultId": "vault-456",
"reshareNonce": 2,
"oldThreshold": 4,
"newThreshold": 4,
"expiresAt": "2026-08-12T22:00:00Z",
"signers": [
{
"id": "signer-b",
"externalId": "operations-mobile",
"changeType": "added",
"oldWeight": 0,
"newWeight": 2,
"publicKey": "abbreviated"
}
]
}
}changeType is added, removed, or kept. Review threshold changes and the old and new weight of every signer before approving.
Common fields
| Field | Meaning |
|---|---|
id | Operation identifier. |
type | sign, keygen, or reshare. |
vaultId | Vault affected by the operation. |
threshold | Required combined signing weight for signing or key generation. |
oldThreshold, newThreshold | Threshold before and after resharing. |
signers[].id | io.sign signer identifier. |
signers[].externalId | Customer-facing identifier when present. |
signers[].weight | Signer's weight for signing or key generation. |
signers[].oldWeight, newWeight | Weight change during resharing. |
signatures[] | Batch of requested signatures. |
metadata.decoded.raw | Wire-oriented decoded transaction fields. |
metadata.decoded.parsed | Normalised values intended for policy evaluation. |
See Custom policy server for the response and failure contract or Open Policy Agent for a tested Rego pattern.
Updated about 2 months ago