Implementation guide for the Velt Approval Engine — a declarative workflow runtime for multi-step agent + human approval processes. Covers the workflow model (definitions = nodes + edges + groups), the 14 REST endpoints under /v2/workflow/* (definitions, executions, steps), webhook delivery with HMAC signature verification, and idempotency/recovery patterns.
When to Apply
Reference these guidelines when:
- Authoring approval workflow definitions — nodes (
agent,human), edges (with optionalwhengating expressions), groups (parallel quorum) - Dispatching executions — always with an
idempotencyKey; configuringwebhookUrl+webhookSecrettogether - Recording decisions — human reviewer approvals/rejections (
/steps/recordReviewerDecision) or external blocking-agent resolutions (/steps/recordAgentResolution) - Building webhook receivers — HMAC-SHA256 signature verification on raw bytes, idempotency on
(executionId, seq), retry schedule, missed-event recovery - Using quorum groups with
waitAll/cancelOnQuorum/joinOnQuorumpolicies - Configuring SLAs (
slaMson a node) and the required breach-routed outgoing edge - Admin-scoped operations (
/steps/cancel,/steps/resolve) - Debugging
INVALID_ARGUMENTlinter rejections (cycle, dangling-edge, unreachable-node, missing-breach-edge, group-joinonquorum-members-must-share-successors)
For general Velt REST API patterns (Comments, Notifications, Activity, etc.), see velt-rest-apis-best-practices — only the Approval Engine domain is covered here.
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Concepts | HIGH | concepts- |
| 2 | REST Endpoints | HIGH | rest- |
| 3 | Webhooks | HIGH | webhooks- |
Quick Reference
Concepts (HIGH)
concepts-workflow-model— definitions = nodes + edges + groups + loops; node shapes (agent / human);reviewerEmails(0–50, surfaces in step output);commentBody(stored on output — engine does NOT auto-create annotations);onRejectshorthand (Form A: routeToNodeId; Form B: loopBack); strict-mode: every human node needs onReject or loop membership; top-levelloops[](loopId, entryNodeId, bodyNodeIds 1–50, maxIterations 1–20, previousAttempts threading); default loop predicatedecision == 'reject' && rejectorMandatory == truedoes NOT fire when step resolved via/steps/resolvereject actions (userecordReviewerDecisioninstead); edgewhenexpressions; group quorum policies (waitAll / cancelOnQuorum / joinOnQuorum)
REST Endpoints (HIGH)
rest-foundations— auth headers, request/response envelope, canonical error codes (includingDEADLINE_EXCEEDED), schema-level validation message referencerest-definitions— 5 endpoints: create / update (withifVersionoptimistic lock) / get / list / delete; full 25-rule linter reference (16 graph+group rules + 9 new loop rules); scope per-level required fields (organizationIdfor organization scope; bothorganizationId+documentIdfor document scope); server-namespaced ID caveat; triggers shape ({ triggerId, eventName?, filters? }) — descriptive metadata only in v1, engine does NOT auto-dispatchrest-executions— 5 endpoints: dispatch (idempotencyKey + webhook config) / get / list / cancel / getEvents (sinceSeq recovery + externally-visible event enumeration cross-referenced to webhooks-delivery, including loop events); v1 list limitation: noorganizationId/documentIdfilter supportrest-steps— 4 endpoints: recordReviewerDecision (unknown reviewer silently accepted as unknown responder — no INVALID_ARGUMENT) / recordAgentResolution / cancel (admin,actorIdREQUIRED 1–256 chars, error matrix: INVALID_ARGUMENT/FAILED_PRECONDITION/NOT_FOUND) / resolve (action-discriminated:force-approve,force-reject,force-complete,force-fail,reviewer-approve,reviewer-reject;actorIdREQUIRED 1–256 chars;reason≤ 2000 chars; reject actions do NOT populaterejectorMandatory— loop predicates won't fire; response shape{ resolved, executionId, stepId, action })rest-object-views— TypeScript shapes forExecutionView,StepView,DefinitionView,ApprovalEventView, the human stepoutputaggregator rollup, and thejoinOnQuorumsuccessor input
Webhooks (HIGH)
webhooks-delivery— HMAC-SHA256 signature verification on raw bytes, delivery headers, retry schedule, event-type catalog (now includesloop.iteration-startedandloop.exhausted), at-least-once idempotencywebhooks-inbound-handler— inbound HTTP endpoint that external systems POST raw JSON to (no{data: ...}envelope), bearer-token auth, signed callback tokens, per-source rate limiting, body-size limits, SSRF URL guard; distinct from outbound delivery and from the deferrednode.type === "webhook"
How to Use
Read individual rule files for detailed explanations and code examples:
rules/shared/concepts/concepts-workflow-model.md
rules/shared/rest/rest-foundations.md
rules/shared/rest/rest-definitions.md
rules/shared/rest/rest-executions.md
rules/shared/rest/rest-steps.md
rules/shared/rest/rest-object-views.md
rules/shared/webhooks/webhooks-delivery.md
rules/shared/webhooks/webhooks-inbound-handler.md
Each rule file contains:
- Brief explanation of why it matters
- Concrete request/response examples
- Common pitfalls and what NOT to do
- Verification checklist
- Source pointers to official docs
Compiled Documents
AGENTS.md— Compressed index of all rules with file paths (start here)AGENTS.full.md— Full verbose guide with all rules expanded inline