Before you start
- Production is the default. Use development or staging only when explicitly scoped, and keep the same authorized organization throughout. Reading this guide performs no action.
- Discover the current published action and validate/plan exact input before any later execution. Confirm the actual mutation and its provider/audit effects.
- Required published permission: app_topolo_engage.workspace:write.
- Resolve an accessible canonical Engage workspace using the current credential. Retain workspace context separately from action input; a settings response contains no workspace identifier and a fixture ID grants no access.
Effects and limits
- Replaces maxPerDay, maxPerWeek and quietHours as one workspace-scoped policy row; this is not a partial patch.
- Caps accept whole numbers 1–100 or null; null disables that cap. quietHours null disables the quiet-hours rule. HH:MM values are 24-hour clocks; a start later than the end spans midnight.
- The recipient timezone selector uses each recipient’s timezone, with fallbackTimezone for missing values. Other timezone values and the fallback must be accepted IANA zones.
- This update changes policy used by later eligibility and sending decisions. It does not send, reserve or recall a message, clear suppression evidence, or authorize outreach.
Request
PUT /api/contactability/policy
Inputs below are source-derived synthetic examples, not approval to execute. Discover resource context separately.
Input fields
| Field | Required | Type and constraints |
|---|---|---|
maxPerDay | Yes | Whole number 1–100, or null to disable the daily cap. |
maxPerWeek | Yes | Whole number 1–100, or null to disable the weekly cap. |
quietHours | Yes | Object with start/end 24-hour HH:MM clocks, timezone (recipient or an accepted IANA zone) and an IANA fallbackTimezone; null disables quiet hours. A window may span midnight. |
Worked examples
Every request/response below is synthetic and unrun, authored from reviewed source and retained published schemas. It is not a captured local or production response. Fixture identities and timestamps authorize nothing.
Replace the complete reviewed settings
SOURCE-DERIVED SYNTHETIC UNRUN example. This is authored illustration, not a captured response, live authorization, provider result or test pass.
Request:
{
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
}
}
Response illustration:
{
"policy": {
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
},
"updatedAt": "2026-10-20T00:00:00.000Z"
}
}
Read the full policy back in the same workspace. Null caps/quietHours disable the respective controls; this does not send or authorize outreach.
Repeat after reconciling the retained row
SOURCE-DERIVED SYNTHETIC UNRUN example. This is authored illustration, not a captured response, live authorization, provider result or test pass.
Request:
{
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
}
}
Response illustration:
{
"policy": {
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
},
"updatedAt": "2026-10-20T00:01:00.000Z"
}
}
Read the full policy back in the same workspace. Null caps/quietHours disable the respective controls; this does not send or authorize outreach.
Clear nullable settings
SOURCE-DERIVED SYNTHETIC UNRUN example. This is authored illustration, not a captured response, live authorization, provider result or test pass.
Request:
{
"maxPerDay": null,
"maxPerWeek": null,
"quietHours": null
}
Response illustration:
{
"policy": {
"maxPerDay": null,
"maxPerWeek": null,
"quietHours": null,
"updatedAt": "2026-10-20T00:00:00.000Z"
}
}
Read the full policy back in the same workspace. Null caps/quietHours disable the respective controls; this does not send or authorize outreach.
Restore separately reviewed previous values
SOURCE-DERIVED SYNTHETIC UNRUN example. This is authored illustration, not a captured response, live authorization, provider result or test pass.
Request:
{
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
}
}
Response illustration:
{
"policy": {
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Europe/London"
},
"updatedAt": "2026-10-20T00:00:00.000Z"
}
}
Read the full policy back in the same workspace. Null caps/quietHours disable the respective controls; this does not send or authorize outreach.
Refuse a semantically invalid policy or window
SOURCE-DERIVED SYNTHETIC UNRUN example. This is authored illustration, not a captured response, live authorization, provider result or test pass. Partial error-code illustration; message text above is explanatory placeholder, not the literal server message.
Request:
{
"maxPerDay": 2,
"maxPerWeek": 5,
"quietHours": {
"start": "20:00",
"end": "08:00",
"timezone": "recipient",
"fallbackTimezone": "Invalid/Example"
}
}
Response illustration:
{
"error": {
"code": "invalid_policy"
}
}
Correct and approve a complete replacement before retrying; no provider/send action is triggered.
Verify the result
- Read contactability.policy.get with the same credential, organization and workspace; compare every setting, not only updatedAt.
- When planning a future separately authorized send, use eligibility.check with discovered recipients to inspect effective limits and suppression. A policy write is not proof of recipient eligibility.
Errors and recovery
- 422
invalid_action_input: Correct the full input using the published schema. HH:MM clocks and explicit nullable fields are required where declared. Validate the corrected request before planning it. - 422
invalid_policy: Inspect the supplied quiet-hours timezone and fallbackTimezone using the accepted IANA/recipient rules; preserve the current policy until a corrected full request is validated and approved. - 403
permission_denied: Stop. The current credential lacks workspace:write for Engage. Do not switch context or broaden permission automatically. - 403
organization_required: Stop and establish the intended authorized organization context. Never add an organization ID to the action input to bypass this refusal. - 409
workspace_required: Discover an accessible canonical Engage workspace through the current credential. A fixture workspace ID grants no access and a body field cannot provision a workspace.
After a lost response, read contactability.policy.get first. If the intended full replacement is already present, do not overwrite it blindly. For a separately reviewed correction or rollback, submit all previous caps and quietHours through this same action, validate and plan it, then read back. Read the current row again before overwriting concurrent changes.
Evidence and change log
- 2026-10-20: Prepared this paired guide from source
767d2d83713809e984559eee562a2c9f7ffcfa4dand the retained production contract snapshot. The source/content review is recorded separately. These examples remain synthetic and unrun; no original response capture or current business-runtime behavior is claimed. - 2026-10-20: First production publication verified after independent source/content review. Removed duplicate introduction and authoring-only status notes; clarified field constraints. Examples remain synthetic and unrun.