publ betaReference (MCP guide)
Open publ console

publ Reference

Migration map.

promotion_notifications_apply

This implementation is a dependency of the documentation branch.

Compose the coupon event's editable web/PWA and app push switches in one save. Omitted switches retain their existing values.

Access and input

Requires the reader's permission and separate notification service configuration, a current observed revision and an active stored coupon event. Source hosted tool and promotion-notifications recovery scopes are selected-channel only.

Input Contract
channelCode Required selected channel code, with the reader's validation.
requestId Required stable identifier matching [A-Za-z0-9_-]{8,80}.
expectedRevision Required current reader digest, exactly 64 lowercase hexadecimal characters.
settings Required strict object containing at least one supported boolean.
settings.isSendPwaPush Optional desired web/PWA push state. Omission preserves it.
settings.isSendAppPush Optional desired app push state. Omission preserves it.
dryRun Optional boolean, default false.

All objects are strict. eventKey, activation, email, third-party flags, receivers, message bodies and financial fields are rejected. Replace the illustrative digest with the returned revision.

{"channelCode":"selected-channel-code","requestId":"coupon-push-001","expectedRevision":"0000000000000000000000000000000000000000000000000000000000000000","settings":{"isSendPwaPush":true,"isSendAppPush":false},"dryRun":true}
{"channelCode":"selected-channel-code","requestId":"coupon-push-001","expectedRevision":"0000000000000000000000000000000000000000000000000000000000000000","settings":{"isSendPwaPush":true,"isSendAppPush":false},"dryRun":false}

Planning and save

The tool first reads stable complete event/app state and verifies expectedRevision. A stale revision returns PROMOTION_NOTIFICATION_CONFLICT. An inactive stored event returns action_required/PROMOTION_NOTIFICATION_DISABLED with writesPerformed:false and an exact console destination; the tool cannot enable the visually locked event. No new journal or mutating business request is created in that path; the checks above still read the current configuration.

A new dry run returns PROMOTION_NOTIFICATIONS_PLAN, changesRequired, sourceBody and writesPerformed:false without a journal or PUT. sourceBody preserves isActivated and isSendEmail, combines the requested switches with omitted values, and sets source constants isSendRealtime:true, receiverType:MEMBER_SINGLE and uniReceiverTypes:[SOURCE_OWNER]. These constants can differ from previously stored values; they are part of the source save contract. A dry run against an existing matching journal reports existingPhase rather than producing a fresh plan.

If requested switch values already match, the actual apply records a completed no-op and sends no PUT. It does not normalize source constants merely to force a write. Otherwise it journals prepared state, repeats complete record/selected app checks, persists save-sent before dispatch, then sends one PUT to the fixed coupon-event path. The notification service must return HTTP 200 data with sendingConfiguration. Its separate acknowledgement contract requires the known positive record id, fixed eventKey, activation/receiver/realtime/app/PWA/email fields; channelId may be omitted. Optional custom key, timestamps and other fields may also be absent. Empty acknowledgement is insufficient. Every returned field except top-level updatedAt must exist in the intended baseline-plus-body and match it; explicit foreign identity, contradictory fields or newly introduced unknown fields are rejected. Missing receipt fields are never fabricated from the baseline.

Completion independently requires a full stable selected GET, including channelId, and the unchanged app indicator. Activation, email, custom message/null and every other unedited JSON business field must survive. Only top-level updatedAt is excluded from comparison across a changed save; when present before, it must still be present after. insertedAt and all other fields remain protected. Full updatedAt remains in snapshots, revision/pre-write checks, no-op records and stored evidence. This exception does not weaken stale-revision rejection. App-indicator drift or incomplete/mismatched content leaves the operation pending. No rollback, notification send or delivery test is performed.

Inputs

Field Required here Contract
settings Yes object
settings.isSendPwaPush No boolean
settings.isSendAppPush No boolean
confirmToken No string; pattern ^ct[a-f\d]{32}$; The confirmToken from this tool's preview result. Omit it to preview; repeat the same input with it to execute.

Results and recovery

Use task status or resume with taskType promotion-notifications and this requestId as taskId. Phases are prepared, save-sent and done. A prepared resume may send the first PUT after guards. Once save-sent is persisted, resume only reconciles by reading the known fixed event; it never repeats a sent PUT. Do not use a new requestId to bypass an uncertain operation.

Completed results have PROMOTION_NOTIFICATIONS_COMPLETE; incomplete results have PROMOTION_NOTIFICATIONS_PENDING. They include phase, historical, noop, writeAcknowledged, writesPerformed and, when saved, the two settings. lastResult explains a pending failure. writesPerformed is false for a no-op/prepared phase, true after the transport returns its accepted acknowledgement, otherwise null; null is uncertainty, not evidence no effect occurred. writeAcknowledged can be true even when subsequent receipt-field validation fails; it is not proof of a valid saved record. An error after save-sent reports outcome:unknown unless an explicit rejected outcome is known, including post-dispatch authentication failures. It must not be read as not_sent. A pending context/permission error may omit normal task content and report journalPersistence.saved instead. A persistence failure must not be treated as a durable recovery guarantee.

Fresh completed verification has confirmed:true and storedCompletion:true. Replaying a completed apply, status or completed resume returns historical:true and confirmed:false; it does not refresh or rewrite completed state. Use get for a new observation. notificationDeliveryVerified, causalityVerified and atomicSnapshot remain false even when matching current state completes recovery.

Reusing a requestId with different input returns REQUEST_ID_CONFLICT. Invalid/inconsistent stored journals return TASK_STATE_UNVERIFIED, and missing tasks return TASK_NOT_FOUND. Checked journal identity, request fingerprint, original revision and progress must agree; do not edit a journal to force success. Missing service configuration, authentication or foreign channel state must be resolved without guessing an origin or resending an uncertain save.

The exact accessible console destination is /channels/{channelCode}/promotion-campaign/notification-settings. Demo omits live destinations. There is no arbitrary event initialization, limited-time-start writer, app installation, consent change or financial action.

Saved plan replay

An existing matching task's dryRun returns a historical saved plan, with historical:true, replayed:true, phase, taskId and false current verification. It has no current console/action link and does not reread target business state, repeat effects or change the journal. Follow nextStep for a current observation; retain the original task ID for status/resume or uncertain-outcome inspection. A new task keeps normal fresh-plan validation.

nextStep: promotion_notifications_get retains the original channel and fixed coupon event. The plan code remains PROMOTION_NOTIFICATIONS_PLAN; existingPhase is retained alongside phase and taskId. No current event/app-indicator read or message delivery occurs. There is no notification activation, installation or financial action.

Saved record identity

A missing record and a malformed existing record are different. If the stored JSON is null, false, zero or an empty string, apply/dry-run/status/resume return TASK_STATE_UNVERIFIED; they do not start new work, replace the record, or report it as absent. Preserve it for operator inspection. Do not delete/edit the record or generate a new request ID to bypass the error. Valid stored work and genuinely missing task IDs keep the recovery behavior described above.