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. Dashboard users can manage the same objects from Approvals.

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
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
rulesobjectOptional rule filters
approversarrayReviewer specification. Supports role reviewers and webhook reviewers.
timeoutSecondsnumberPending request lifetime
defaultOnTimeoutstringreject or expire
approvalAccessModestringdashboard_only, dashboard_and_hosted_link, or hosted_link_only

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
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

Update policy

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

Send any policy fields to update.

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": "[email protected]",
      "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
dashboardUrlstring | nullDashboard approval page when the mode allows dashboard access
idempotencyKeystring | nullKey to reuse when retrying
expiresAtstringExpiry timestamp

Hosted approval links are bearer links. Use dashboard_only for stricter review flows, or 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, up to 100

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.

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 dashboard/API 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": "[email protected]",
      "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",
          "approvalAccessMode": "dashboard_and_hosted_link",
          "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 approvals with different access modes, 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)