events.iterate.com

Event type

events.iterate.com/project/human-approval-decided

THE verdict on a held batch — one event decides every request in it, by index. When the project has active approval keys, a decision containing any `approve` verdict must carry `keyId` + `signature` (raw 64-byte r‖s ECDSA P-256 over the canonical approval.v2 message, base64) or the whole event is ignored. All-reject decisions never need a signature — deny is the fail-safe direction. The door honors the FIRST decided event referencing a batch; later ones are ignored.

Payload schema

approvalRequestEventOffsetinteger

The batch's identity: the offset of its human-approval-requested event.

verdicts("approve" | "reject")[]

One verdict per request, same order as the batch's `requests` array. A count mismatch makes the event malformed and ignored.

decidedBy"human" | "expiry"

Who decided: a human, or the door's own timeout (expiry is always all-reject and never signed).

reasonstringoptional

The human's stated reason, applying to every rejected index in this decision. It rides back to the calling script in each rejected fetch's 403 body, so the agent can read why and retry with a change. Deliberately NOT covered by the approval.v2 signature: rejections never need signatures (deny is the fail-safe direction — stream-append access already suffices to veto), so signing the reason would protect nothing. Expiry decisions never carry one.

keyIdstringoptional

The enrolled key that signed this decision.

signaturestringoptional

Base64 raw 64-byte r‖s ECDSA P-256 signature over the canonical approval.v2 message.

Raw JSON schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "approvalRequestEventOffset": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991,
      "description": "The batch's identity: the offset of its human-approval-requested event."
    },
    "verdicts": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "approve",
          "reject"
        ]
      },
      "description": "One verdict per request, same order as the batch's `requests` array. A count mismatch makes the event malformed and ignored."
    },
    "decidedBy": {
      "type": "string",
      "enum": [
        "human",
        "expiry"
      ],
      "description": "Who decided: a human, or the door's own timeout (expiry is always all-reject and never signed)."
    },
    "reason": {
      "description": "The human's stated reason, applying to every rejected index in this decision. It rides back to the calling script in each rejected fetch's 403 body, so the agent can read why and retry with a change. Deliberately NOT covered by the approval.v2 signature: rejections never need signatures (deny is the fail-safe direction — stream-append access already suffices to veto), so signing the reason would protect nothing. Expiry decisions never carry one.",
      "type": "string",
      "minLength": 1,
      "maxLength": 1000
    },
    "keyId": {
      "description": "The enrolled key that signed this decision.",
      "type": "string"
    },
    "signature": {
      "description": "Base64 raw 64-byte r‖s ECDSA P-256 signature over the canonical approval.v2 message.",
      "type": "string"
    }
  },
  "required": [
    "approvalRequestEventOffset",
    "verdicts",
    "decidedBy"
  ]
}