Require step-up
- Type
- require_step_up
- Category
- Agent safety
- Enforced atWhen this policy is checked: while someone tries to open, while they create or change an invitation or hold, or after a denial (notify only).
- Access-time
- TiersWhere an admin can set this policy: the whole organization, one integration, or the physical device when the connector supports a device steward.
- OrgIntegration
- EnforcementHow a configured row behaves. Enforce blocks. Require approval opens an admin inbox when the type supports it. Audit only records and never blocks.
- Enforce
- DefaultWhat happens when no row of this type is configured.
- Not configured — no extra confirmation beyond ordinary authorization.
Requires an extra confirmation step before a physical write (for example opening a door) for the listed principal kinds. Human admins are not included unless applies_to says so. Use this so an agent or API key cannot move hardware on a single unattended call.
When it is enforced
Evaluated when someone opens a door or gate or triggers an entity action. If this policy applies, the open is denied even when roles and grants would otherwise allow it.
Where to set it
Settings → Policies (org) or the integration Policies tab.
Policies never grant access. See thepolicies architecture guidefor how org, integration, and device tiers combine.
Arguments
The config object on create/update. Shared row fieldsenforcement (enforce, require_approval,audit_only) and enabled apply to every type;audit_only and disabled rows never block.
| Name | Type | Required | Values | Description |
|---|---|---|---|---|
| applies_to | string or string[] | No | agentapi_keyinvitationmemberresidentadminall | Principal kinds this row binds. Closed set: agent, api_key, invitation, member, resident, admin, all. Unknown strings and empty arrays are rejected. `all` matches every kind. When omitted, the type-specific default applies (see Default). Device-tier rows without `applies_to` often bind everyone, including admins. Default: agent, api_key, invitation |
| output | string or integer | No | — | Optional channel or output id. When set, the policy binds only that output. When omitted, it binds every output of the tier target. A scoped row does not apply when the acting output is unknown. |
How overlapping rows combine
Boolean OR across applicable enforcing rows (any require-step-up wins).
Example
An API key must send the extra confirmation header before switchable.open succeeds. A resident opening from the portal is unaffected.
{ "applies_to": [ "agent", "api_key" ]}Integrations
This type is documented on these connectors:
- Home Assistant (home_assistant)
- KNX (knx)
- MQTT (mqtt)
- PalGate Cloud (palgate_cloud)
- Shelly Cloud (shelly_cloud)
- Shelly Websocket (shelly_websocket)
- Tasmota (tasmota)
- Virtual Access (virtual_access)
- Virtual Demo Devices (virtual_demo)
- Waveshare (waveshare)
Related
- Policy catalog
- Policies architecture guide
- Rate limit (rate_limit)
- Quiet hours (quiet_hours)
- Emergency lockdown (emergency_lockdown)
Typed configuration
Section titled “Typed configuration”The generated OpenAPI document exposes the config object as
RequireStepUpPolicyConfig. applies_to accepts one principal kind or an array
of principal kinds; the array form is canonical for generated clients. output
is optional and accepts a provider-derived channel or output id (string or
integer).
{ "applies_to": ["agent", "api_key"], "output": "main"}Unknown or empty principal selectors are rejected. Omit applies_to to use the
policy’s default principal set, or omit output to apply it to every output of
the tier target.
Confirmation protocol
Section titled “Confirmation protocol”require_step_up currently uses the authenticated preview-confirmation protocol. It
is an additional confirmation of the exact write request, not an independent
second factor or a replacement for MFA.
- Call
POST /entities/{id}/actions/{action_id}/previewwith the exact JSON payload that will be executed. - If confirmation is required, the response includes
preview_token. - Repeat the same request at
POST /entities/{id}/actions/{action_id}with the token inX-OpenApp-Confirm.
The token is short-lived (10 minutes), single-use, and bound to the organization, authenticated principal, entity, action id, and exact JSON payload. A missing, expired, replayed, cross-principal, cross-entity, cross-action, or payload-mismatched token is rejected. A boolean header or a random ULID is not a valid proof. The preview does not call the hardware provider; the execute request is the only call that performs the physical write.
The proof is issued only after ordinary authentication and authorization succeed. Deployments that require a separate second factor must enforce that requirement in their authentication or credential layer; this policy does not claim to provide MFA.