Approvals

Create Human Gates policies, list approval requests, and record approval decisions.

Approvals

Approvals power Human Gates. A policy decides when execution should pause; an approval request is the pending review item created when a policy matches.

Use approval APIs when you build your own SaaS control plane or need programmatic reviewer workflows. Users can manage the same objects from the Weavz UI.

Approval policy object

FieldTypeDescription
idstringPolicy ID
workspaceIdstring | nullWorkspace scope. null applies organization-wide.
namestringHuman-readable policy name
descriptionstring | nullOptional policy description
enabledbooleanWhether the policy can match execution
prioritynumberLower values run first
sourcesstring[]Execution sources: rest, sdk, mcp_tools, mcp_code, playground, trigger
mcpServerIdsstring[]Optional MCP server filters
workspaceIntegrationIdsstring[]Optional configured workspace integration filters
integrationNamesstring[]Optional integration filters
integrationAliasesstring[]Optional workspace integration alias filters
actionNamesstring[]Optional action filters
connectionStrategiesstring[]Optional fixed, per_user, or per_user_with_fallback filters
endUserModestringany, end_user_present, or no_end_user
decisionstringrequire_approval, notify_only, block, or auto_approve
riskModestringrules, always, or model_assisted
rulesobjectOptional rule filters
approversarrayReviewer specification. Supports role reviewers and webhook reviewers.
timeoutSecondsnumberPending request lifetime
defaultOnTimeoutstringreject or expire
reuseWindowSecondsnumberOptional window for reusing a previous approval decision
approvalAccessModestringdashboard_only, dashboard_and_hosted_link, or hosted_link_only
metadataobjectOptional policy metadata

When multiple policies match the exact same action, Weavz applies the highest-priority matching policy. Lower priority values win; ties use the most severe decision, then policy ID. Use one broad policy when a single reviewer decision should cover an action, or split policies by integration alias/action when you need separate approvals.

Create policy

POST/api/v1/approval-policies

Request Body

FieldTypeRequiredDefaultDescription
workspaceIdstring (uuid)Noorg-wideOptional workspace scope
namestringYes-Policy name, max 120 chars
descriptionstringNo-Optional description, max 1000 chars
enabledbooleanNotrueWhether the policy can match execution
priorityintegerNo100Lower values run first, from 0 to 10000
sourcesstring[]No["rest", "sdk", "mcp_tools", "mcp_code"]Execution sources: rest, sdk, mcp_tools, mcp_code, playground, trigger
mcpServerIdsstring[]No[]Restrict matching to specific MCP servers
workspaceIntegrationIdsstring[]No[]Restrict matching to configured workspace integrations
integrationNamesstring[]No[]Restrict matching to integration names
integrationAliasesstring[]No[]Restrict matching to workspace integration aliases
actionNamesstring[]No[]Restrict matching to action names
connectionStrategiesstring[]No[]Restrict to fixed, per_user, or per_user_with_fallback
endUserModestringNoanyany, end_user_present, or no_end_user
decisionstringNorequire_approvalrequire_approval, notify_only, block, or auto_approve
riskModestringNorulesalways, rules, or model_assisted
rulesobjectNo{}Rule filters. Supported fields include actionCategories, amountThresholds, recipientAllowlist, recipientDenylist, domainAllowlist, domainDenylist, and storagePathPrefixes
approversarrayNo[]Reviewer specs. Use org_role, dashboard_user, end_user, or webhook
timeoutSecondsintegerNo3600Pending request lifetime, from 60 seconds to 30 days
defaultOnTimeoutstringNorejectreject or expire
reuseWindowSecondsintegerNo-Optional reuse window, from 0 seconds to 7 days
approvalAccessModestringNodashboard_and_hosted_linkdashboard_only, dashboard_and_hosted_link, or hosted_link_only
metadataobjectNo-Optional policy metadata

Approver shapes

TypeRequired fieldsNotes
org_rolerolesRoles can be owner, admin, or member
dashboard_useruserIdsDashboard user IDs
end_usernoneRoutes review to the end-user context when available
webhookwebhookUrlMust be a public HTTPS URL
bash
curl -X POST https://api.weavz.io/api/v1/approval-policies \
  -H "Authorization: Bearer wvz_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Review MCP code actions",
    "sources": ["mcp_code"],
    "decision": "require_approval",
    "riskMode": "always",
    "approvers": [{ "type": "org_role", "roles": ["owner", "admin"] }],
    "timeoutSeconds": 3600
  }'

Response:

json
{
  "policy": {
    "id": "2c7f6e97-6d1e-4c5c-85f3-ffbbfcf404e5",
    "name": "Review MCP code actions",
    "enabled": true,
    "sources": ["mcp_code"],
    "decision": "require_approval"
  }
}

List policies

GET/api/v1/approval-policies

Query parameters:

ParameterTypeDescription
workspaceIdstringOptional workspace filter

Get policy

GET/api/v1/approval-policies/:id

Returns one approval policy.

bash
curl https://api.weavz.io/api/v1/approval-policies/2c7f6e97-6d1e-4c5c-85f3-ffbbfcf404e5 \
  -H "Authorization: Bearer wvz_your_api_key"

Update policy

PATCH/api/v1/approval-policies/:id

Send any policy fields to update.

The update body accepts the same fields as create, all optional. Array filters replace the stored arrays when provided.

bash
curl -X PATCH https://api.weavz.io/api/v1/approval-policies/policy_id \
  -H "Authorization: Bearer wvz_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

Delete policy

DELETE/api/v1/approval-policies/:id

Deletes the policy. Existing approval request history remains available.

Test policy matching

POST/api/v1/approval-policies/test

Use this endpoint before enabling a policy in production.

json
{
  "policy": {
    "name": "Review per-user actions",
    "sources": ["sdk"],
    "connectionStrategies": ["per_user"],
    "decision": "require_approval"
  },
  "context": {
    "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
    "source": "sdk",
    "integrationName": "gmail",
    "integrationAlias": "user_mail",
    "actionName": "send_email",
    "connectionStrategy": "per_user",
    "input": {
      "to": "customer@example.com",
      "subject": "Follow up"
    }
  }
}

Response:

json
{
  "decision": "require_approval",
  "matched": true,
  "reasons": [
    "source matched sdk",
    "connection strategy matched per_user"
  ]
}

Approval request object

FieldTypeDescription
idstringApproval request ID, prefixed with apr_
policyIdstring | nullMatched policy
workspaceIdstring | nullWorkspace scope
endUserIdstring | nullEnd user whose connection may be used
sourcestringExecution source
statusstringpending, approved, rejected, expired, canceled, or consumed
integrationNamestringIntegration name
integrationAliasstring | nullWorkspace integration alias
actionNamestringAction name
inputPreviewobjectRedacted input preview
redactedPathsstring[]Paths hidden from review
riskReasonsstring[]Policy match reasons
approvalAccessModestringdashboard_only, dashboard_and_hosted_link, or hosted_link_only
approvalUrlstring | nullApproval URL allowed by the policy mode
hostedApprovalUrlstring | nullTokenized hosted approval page when the mode allows hosted links
idempotencyKeystring | nullKey to reuse when retrying
expiresAtstringExpiry timestamp

Hosted approval links are bearer links. Allow hosted links when an external MCP client, SDK user, or customer-owned app needs a URL it can route to reviewers.

List approval requests

GET/api/v1/approvals

Query parameters:

ParameterTypeDescription
workspaceIdstringOptional workspace filter
statusstringOptional approval status
sourcestringOptional execution source
integrationNamestringOptional integration filter
actionNamestringOptional action filter
limitnumberMaximum records to return, default 50, up to 100
cursorstringPagination cursor

Get approval request

GET/api/v1/approvals/:id

Returns one approval request.

Approve request

POST/api/v1/approvals/:id/approve

Approves a pending request and creates a receipt for the exact retry.

Decision requests accept optional reason and metadata fields. The same body shape is accepted by approve, reject, and cancel endpoints.

bash
curl -X POST https://api.weavz.io/api/v1/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0/approve \
  -H "Authorization: Bearer wvz_backend_key" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Reviewed customer-facing message." }'

The API key used to approve must have Human Gates decision permission for the request's workspace or organization scope.

Reject request

POST/api/v1/approvals/:id/reject

Rejects a pending request. Retrying the original action will create a new approval request if the policy still matches.

Cancel request

POST/api/v1/approvals/:id/cancel

Cancels a pending request without approving execution.

Webhook approvers

Webhook approvers let your own app receive approval lifecycle events and route a reviewer to a hosted approval page.

json
{
  "name": "Review agent sends",
  "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
  "sources": ["sdk", "mcp_tools", "mcp_code"],
  "decision": "require_approval",
  "riskMode": "always",
  "approvers": [
    {
      "type": "webhook",
      "webhookUrl": "https://app.example.com/weavz/approvals"
    }
  ]
}

Webhook URLs must be public HTTPS URLs.

Events:

EventWhen it is sent
approval.requestedA new approval request is created
approval.approvedA reviewer approves the request
approval.rejectedA reviewer rejects the request
approval.canceledA reviewer cancels the request
approval.expiredA pending request is marked expired

Payload example:

json
{
  "event": "approval.requested",
  "createdAt": "2026-05-14T12:00:00.000Z",
  "approval": {
    "id": "apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0",
    "status": "pending",
    "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
    "source": "mcp_code",
    "integrationName": "gmail",
    "integrationAlias": "customer_mail",
    "actionName": "send_email",
    "inputPreview": {
      "to": "customer@example.com",
      "subject": "Follow up",
      "apiKey": "[REDACTED]"
    },
    "redactedPaths": ["apiKey"],
    "riskReasons": ["source matched mcp_code"],
    "approvalUrl": "https://platform.weavz.io/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0",
    "hostedApprovalUrl": "https://platform.weavz.io/approve/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0?token=apr_link_...",
    "api": {
      "detailUrl": "https://api.weavz.io/api/v1/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0",
      "approveUrl": "https://api.weavz.io/api/v1/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0/approve",
      "rejectUrl": "https://api.weavz.io/api/v1/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0/reject",
      "cancelUrl": "https://api.weavz.io/api/v1/approvals/apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0/cancel"
    },
    "codeRun": {
      "type": "mcp_code_batch_run",
      "codeRunId": "crun_4f7b...",
      "codeHash": "sha256...",
      "toolSurfaceHash": "sha256...",
      "approvalGroups": [
        {
          "approvalPolicyId": "pol_...",
          "approvalPolicyName": "Review customer-visible sends",
          "tools": []
        }
      ],
      "analysisConfidence": "exact",
      "dynamicSignals": [],
      "continuation": {
        "tool": "weavz_execute",
        "arguments": { "approvalId": "apr_9b36d3f761d84bb2b6f9a0c4b9d1f7e0" }
      }
    },
    "idempotencyKey": "ticket-421-send",
    "expiresAt": "2026-05-14T13:00:00.000Z"
  },
  "receipt": null
}

Delivery headers:

HeaderDescription
X-Weavz-EventLifecycle event name
X-Weavz-DeliveryUnique delivery ID
X-Weavz-AttemptDelivery attempt number
X-Weavz-ApprovalApproval request ID
X-Weavz-TimestampUnix timestamp when webhook signing is enabled
X-Weavz-Signaturet=<timestamp>,v1=<hmac> when webhook signing is enabled

For signed deliveries, verify the HMAC over <timestamp>.<raw JSON body> and reject stale timestamps. The webhook payload includes the redacted action preview only; raw action input and connection credentials are never sent.

Developer platforms can use webhook approvers as approval callbacks: store approval.id, render approval.inputPreview and approval.codeRun in their own UI, then call approval.api.approveUrl or approval.api.rejectUrl with an API key that has approvals.decide. API decision URLs are not bearer URLs; they still require normal API authentication.

For MCP Code Mode, approval requests may represent a batch run instead of one explicit tool call. In that case approval.inputPreview has type: "mcp_code_batch_run" and includes deterministic reviewer context such as codeRunId, intentSummary, impactSummary, predictedTools, approvalRequiredTools, approvalGroups, availableApps, externalDomains, storageIndicators, analysisConfidence, dynamicSignals, codeHash, and toolSurfaceHash. codeRunId is stable across approval requests for the same stored Code Mode run, so customer-owned approval UIs can group sibling approvals without inferring from hashes. approvalGroups shows which policy decision covers which predicted calls. If a Code Mode run needs multiple approvals, the MCP response includes an approvals array and an approvalGroup summary; after each decision, call weavz_execute or /api/v1/mcp/servers/:id/execute-code with only { "approvalId": "apr_..." } and Weavz will return the next pending approval or the final result.

The approval detail API also includes recent webhookDeliveries when lifecycle notifications were configured, so customer dashboards can show whether callbacks were sent, failed, or retried.

SDK resources

TypeScript:

typescript
const { policies } = await client.approvalPolicies.list({ workspaceId })
const { policy } = await client.approvalPolicies.create({ name, sources: ['mcp_tools'] })
const { approvals } = await client.approvals.list({ status: 'pending' })
await client.approvals.approve(approvalId, { reason: 'Reviewed.' })
await client.approvals.wait(approvalId)

Python:

python
policies = client.approval_policies.list(workspace_id=workspace_id)
created = client.approval_policies.create(name="Review MCP", sources=["mcp_tools"])
pending = client.approvals.list(status="pending")
client.approvals.approve(approval_id, reason="Reviewed.")
client.approvals.wait(approval_id)