publ betaReference (MCP guide)
Open publ console

publ Reference

Migration map.

questionnaire_apply

See the current correction and older-server guidance before preparing new inputs; keep existing task inputs unchanged during recovery.

This implementation is a dependency of the documentation branch.

Create or revise a full questionnaire through one composed workflow, including ordered questions/options and optional original images. Use visibility to activate or deactivate existing records.

Access and input

Requires OWNER or DELEGATEE with MANAGE_MARKETING_TOOLS on the selected channel. The source has no questionnaire plan or connected-domain gate. Hosted selected-channel resources admit these tools only for the exact channelCode; account resources exclude them.

channelCode and questionnaire/answer IDs are strings of 1–512 characters, excluding literal dot/double dot, slash, backslash, ASCII controls and DEL. Obtain them from authorized discovery/results; numeric row IDs, URLs and credentials are not substitutes. Strict input objects reject unknown properties.

Input Contract
channelCode Required selected channel code.
requestId Required 8–80 ASCII letters, digits, underscores or hyphens; preserve for recovery.
action create or revise.
qrid Required for revise; forbidden for create.
expectedRevision Required 64 lowercase hexadecimal characters from creationRevision (create) or detail revision (revise).
settings Required nonempty strict object described below.
dryRun Optional boolean, defaults to false. true checks/prepares without business effects or task JSON. A local empty lock directory may be created.

Action combinations and nonempty settings are runtime refinements beyond the flat JSON Schema. The all-zero revisions and illustrative IDs below must be replaced with current authorized reader values. All examples are dry runs.

{
  "channelCode": "selected-channel-code",
  "requestId": "questionnaire-create-01",
  "action": "create",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "settings": {
    "title": "Feedback",
    "titleDisplay": "Share your feedback",
    "description": "Tell us about your experience.",
    "isGuestAnswerAllowed": false,
    "isDuplicateAnswerAllowed": false,
    "backgroundColorInHex": "#f5f5f8",
    "questions": [
      {
        "title": "Your topic",
        "type": "SHORT_ANSWER",
        "isEssential": true,
        "hintText": "A short summary"
      },
      {
        "title": "Your experience",
        "type": "LONG_ANSWER",
        "isEssential": false
      },
      {
        "title": "Choose a category",
        "type": "RADIO",
        "isEssential": true,
        "options": [
          {
            "label": "Product"
          },
          {
            "label": "Support"
          }
        ]
      },
      {
        "title": "Topics of interest",
        "type": "CHECKBOX",
        "isEssential": false,
        "options": [
          {
            "label": "Updates"
          }
        ]
      },
      {
        "title": "Preferred contact",
        "type": "DROPDOWN",
        "isEssential": false,
        "options": [
          {
            "label": "Email"
          },
          {
            "label": "None"
          }
        ]
      }
    ]
  },
  "dryRun": true
}

Settings and ordered replacement

Field Contract
settings.title Trimmed 1–50 characters; required for creation, otherwise optional.
settings.titleDisplay Optional trimmed string up to 200 characters; empty is allowed.
settings.description Optional string up to 2,000 characters; empty clears it.
settings.isGuestAnswerAllowed Optional boolean; the composed result requires duplicate answers when true.
settings.isDuplicateAnswerAllowed Optional boolean; must be true when guests are enabled.
settings.backgroundColorInHex Optional #RGB, #RGBA, #RRGGBB or #RRGGBBAA, case-insensitive.
settings.questions Optional ordered array of 0–100 questions; supplying it replaces the entire list.
settings.coverImage Optional original image object, null to remove, or omission to preserve.
settings.coverImage.filename PNG/JPEG filename, 1–240 characters; no path separators, colon or controls.
settings.coverImage.base64 Canonical base64 of original PNG/JPEG bytes; see image limits below.

Creation defaults titleDisplay to title, description to empty, active state to true, guest/duplicate answers to false, backgroundColorInHex to #f5f5f8, and questions to empty. The console has a localized default description; supply the intended localized text explicitly. This tool does not infer locale. Omitted settings on revision preserve existing values; empty arrays and explicit null have different meanings from omission.

Each settings.questions[] is strict and uses these fields:

Question field Contract
settings.questions[].qid Optional existing string identity.
settings.questions[].id Optional existing positive safe-integer identity.
settings.questions[].title Required string, up to 16,384 characters for text types; up to 200 for choices.
settings.questions[].description Optional string, up to 16,384 characters for text types; up to 2,000 for choices.
settings.questions[].isEssential Required boolean.
settings.questions[].type SHORT_ANSWER, LONG_ANSWER, RADIO, CHECKBOX or DROPDOWN.
settings.questions[].hintText Optional string up to 16,384 characters; intended for text questions. The schema also accepts it on choices.
settings.questions[].hasSubTextField Optional boolean for choices; forbidden on text types, true forbidden for DROPDOWN.
settings.questions[].options Required choice array: 2–30 for RADIO/DROPDOWN, 1–30 for CHECKBOX; forbidden on text types.
settings.questions[].options[].label Required trimmed nonempty string up to 16,384 characters; unique after trimming within the question.
settings.questions[].options[].existingOrder Optional positive safe integer identifying an existing option in this retained question; no duplicate references.
settings.questions[].options[].image Optional original image, null removal or omission preservation.
settings.questions[].options[].image.filename Same filename rules as coverImage.filename.
settings.questions[].options[].image.base64 Canonical original PNG/JPEG bytes, with the smaller option-image limit.

Retain a question with qid and/or id; both must match the same existing question when supplied. Each existing question can be retained once. A question without either identity is new. Existing types cannot be changed in place: omit the old question and add a new one without an old identity. Omitted questions/options are removed by replacement. Question and option order is recomputed from array order starting at 1. existingOrder preserves the selected option's image and unknown business fields while permitting label/reordering changes. Omitted question description/hint and hidden source fields are preserved. A stored null question description or cover reference remains null when omitted; this does not permit null in the writable description input. Explicit image removal still produces the empty source reference. UI helpers question.uuid and option.value are removed from the submitted DTO.

The 100-question and 16,384-character text/label caps are bridge limits for source-unbounded controls. Runtime composition rejects unknown/mismatched/duplicated retained identities and invalid guest/duplicate combinations. A supplied questions array is the complete desired list, not a patch.

{
  "channelCode": "selected-channel-code",
  "requestId": "questionnaire-revise-01",
  "action": "revise",
  "qrid": "selected-questionnaire-id",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "settings": {
    "title": "Updated feedback",
    "coverImage": null,
    "questions": [
      {
        "qid": "selected-question-id",
        "title": "Choose a category",
        "type": "RADIO",
        "isEssential": true,
        "options": [
          {
            "label": "Support",
            "existingOrder": 2
          },
          {
            "label": "Product",
            "existingOrder": 1,
            "image": null
          }
        ]
      }
    ]
  },
  "dryRun": true
}

Images and service prerequisites

Images must contain structurally validated original PNG/JPEG bytes. Filename extensions are case-insensitive at runtime; the JSON-exported regex omits that flag, so use lowercase extensions for portability. No data URL or arbitrary image URL is accepted. Cover bytes must be strictly below 10 MiB, each option image strictly below 2 MiB. All replacement images together must be below 10 MiB per request, a bridge cap. The shared exported image object has the cover base64 bound (13,981,012 characters); option byte limits, canonical base64, structure and aggregate size are enforced at runtime. Split larger changes into separately read/revised operations.

A larger envelope does not raise those tools' individual image limits.

The host configures the normal API origin. Replacing images additionally needs the resource gateway, bucket and region before any effect, including when planning. The workflow obtains channel-scoped grants accepting HTTP200/201 data, validates the configured upload grant, and uploads checked original bytes sequentially. An older uncertain grant is never retried by this correction. Only verified receipt locations enter the full DTO; byte length and checksum must match. Journals retain metadata/receipts, never original bytes, base64 or upload credentials. Null stores an empty image reference; omission preserves it. No automatic orphan deletion or rollback occurs.

{
  "channelCode": "selected-channel-code",
  "requestId": "questionnaire-image-01",
  "action": "revise",
  "qrid": "selected-questionnaire-id",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "settings": {
    "coverImage": {
      "filename": "cover.png",
      "base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aDWQAAAAASUVORK5CYII="
    }
  },
  "dryRun": true
}

Inputs

Field Required here Contract
action Yes create, revise
qrid No string; min length 1; max length 512
settings Yes object
settings.title No string; min length 1; max length 50
settings.titleDisplay No string; max length 200
settings.description No string; max length 2000
settings.isGuestAnswerAllowed No boolean
settings.isDuplicateAnswerAllowed No boolean
settings.backgroundColorInHex No string; pattern ^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
settings.questions No array; max items 100
settings.questions[].qid No string; min length 1; max length 512
settings.questions[].id No integer; greater than 0
settings.questions[].title Yes string; max length 16384
settings.questions[].description No string; max length 16384
settings.questions[].isEssential Yes boolean
settings.questions[].type Yes SHORT_ANSWER, LONG_ANSWER, RADIO, CHECKBOX, DROPDOWN
settings.questions[].hintText No string; max length 16384
settings.questions[].hasSubTextField No boolean
settings.questions[].options No array; max items 30
settings.questions[].options[].label Yes string; min length 1; max length 16384
settings.questions[].options[].existingOrder No integer; greater than 0
settings.questions[].options[].image No one of: local-file, more-parts, complete, cancel (by kind); Upload the image from this computer: {kind:"local-file", filename, byteLength, sha256} returns one presigned PUT (size, type and SHA-256 signed) and the console link; send the file, then call again with the same input and this field set to {kind:"complete", uploadId, parts:[{partNumber:1, etag}]}. The server never receives the file or downloads a link; download a link to this computer first. or null
settings.questions[].options[].image.filename Yes When settings.questions[].options[].image.kind is local-file: string; min length 1; max length 240; pattern ^[^/\\:\x00-\x1f\x7f]+$; The name of the file on this computer, with its extension.
settings.questions[].options[].image.byteLength Yes When settings.questions[].options[].image.kind is local-file: integer; greater than 0; The exact file size in bytes (for example from wc -c < FILE or stat).
settings.questions[].options[].image.sha256 No When settings.questions[].options[].image.kind is local-file: string; pattern ^[0-9a-f]{64}$; The SHA-256 of the file in lowercase hex (shasum -a 256 FILE). Required when the upload answers UPLOAD_CHECKSUM_REQUIRED.
settings.questions[].options[].image.uploadId Yes When settings.questions[].options[].image.kind is more-parts: string; pattern ^upl_[A-Za-z0-9_-]{22}$
settings.questions[].options[].image.fromPart Yes When settings.questions[].options[].image.kind is more-parts: integer; minimum 1; maximum 10000
settings.questions[].options[].image.uploadId Yes When settings.questions[].options[].image.kind is complete: string; pattern ^upl_[A-Za-z0-9_-]{22}$
settings.questions[].options[].image.parts Yes When settings.questions[].options[].image.kind is complete: array; min items 1; max items 10000
settings.questions[].options[].image.parts[].partNumber Yes When settings.questions[].options[].image.kind is complete: integer; minimum 1; maximum 10000
settings.questions[].options[].image.parts[].etag Yes When settings.questions[].options[].image.kind is complete: string; min length 1; max length 200
settings.questions[].options[].image.measured No When settings.questions[].options[].image.kind is complete: object; What the video measures on this computer, read with measureCommand.
settings.questions[].options[].image.measured.durationSeconds Yes When settings.questions[].options[].image.kind is complete: number; maximum 1000000; greater than 0; Video duration in seconds (ffprobe format.duration).
settings.questions[].options[].image.measured.frameRate Yes When settings.questions[].options[].image.kind is complete: number; maximum 1000; greater than 0; Frames per second (ffprobe avg_frame_rate, for example 30000/1001 = 29.97).
settings.questions[].options[].image.measured.width Yes When settings.questions[].options[].image.kind is complete: integer; maximum 100000; greater than 0
settings.questions[].options[].image.measured.height Yes When settings.questions[].options[].image.kind is complete: integer; maximum 100000; greater than 0
settings.questions[].options[].image.measured.frameRateMode No When settings.questions[].options[].image.kind is complete: CFR, VFR; Constant or variable frame rate, when the tool reports it.
settings.questions[].options[].image.measured.minFrameRate No When settings.questions[].options[].image.kind is complete: number; maximum 1000; greater than 0
settings.questions[].options[].image.measured.maxFrameRate No When settings.questions[].options[].image.kind is complete: number; maximum 1000; greater than 0
settings.questions[].options[].image.uploadId Yes When settings.questions[].options[].image.kind is cancel: string; pattern ^upl_[A-Za-z0-9_-]{22}$
settings.coverImage No one of: local-file, more-parts, complete, cancel (by kind) or null
settings.coverImage.filename Yes When settings.coverImage.kind is local-file: string; min length 1; max length 240; pattern ^[^/\\:\x00-\x1f\x7f]+$; The name of the file on this computer, with its extension.
settings.coverImage.byteLength Yes When settings.coverImage.kind is local-file: integer; greater than 0; The exact file size in bytes (for example from wc -c < FILE or stat).
settings.coverImage.sha256 No When settings.coverImage.kind is local-file: string; pattern ^[0-9a-f]{64}$
settings.coverImage.uploadId Yes When settings.coverImage.kind is more-parts: string; pattern ^upl_[A-Za-z0-9_-]{22}$
settings.coverImage.fromPart Yes When settings.coverImage.kind is more-parts: integer; minimum 1; maximum 10000
settings.coverImage.uploadId Yes When settings.coverImage.kind is complete: string; pattern ^upl_[A-Za-z0-9_-]{22}$
settings.coverImage.parts Yes When settings.coverImage.kind is complete: array; min items 1; max items 10000
settings.coverImage.parts[].partNumber Yes When settings.coverImage.kind is complete: integer; minimum 1; maximum 10000
settings.coverImage.parts[].etag Yes When settings.coverImage.kind is complete: string; min length 1; max length 200
settings.coverImage.measured No When settings.coverImage.kind is complete: object; What the video measures on this computer, read with measureCommand.
settings.coverImage.measured.durationSeconds Yes When settings.coverImage.kind is complete: number; maximum 1000000; greater than 0; Video duration in seconds (ffprobe format.duration).
settings.coverImage.measured.frameRate Yes When settings.coverImage.kind is complete: number; maximum 1000; greater than 0; Frames per second (ffprobe avg_frame_rate, for example 30000/1001 = 29.97).
settings.coverImage.measured.width Yes When settings.coverImage.kind is complete: integer; maximum 100000; greater than 0
settings.coverImage.measured.height Yes When settings.coverImage.kind is complete: integer; maximum 100000; greater than 0
settings.coverImage.measured.frameRateMode No When settings.coverImage.kind is complete: CFR, VFR
settings.coverImage.measured.minFrameRate No When settings.coverImage.kind is complete: number; maximum 1000; greater than 0
settings.coverImage.measured.maxFrameRate No When settings.coverImage.kind is complete: number; maximum 1000; greater than 0
settings.coverImage.uploadId Yes When settings.coverImage.kind is cancel: string; pattern ^upl_[A-Za-z0-9_-]{22}$
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 full readback

A new dry run returns success / QUESTIONNAIRE_PLAN with noop, changes and plannedStages; writesPerformed is false and verification.confirmed is false. Planning does not reserve a future revision. The workflow compares full content twice, verifies channel/credential continuity, checks the supplied revision, and repeats preservation checks before every effect.

An actual no-op records done without upload/save. Otherwise it sends one full create POST or known-ID revise POST after any uploads; creation accepts HTTP200/201 data, while revision still requires HTTP200 data. Other success statuses are not implicitly accepted. There is no recache. Creation requires returned positive id, qrid and channelId equal to the selected channel. Full readback checks requested fields, retained identities and all untouched business fields, including their supported null representations. Question arrays must have the exact requested length and match after sorting by explicit question order. Ambiguous question order/identity and duplicate option order reject. Option arrays retain their source positions and must match the requested order. New server IDs/defaults may be added. answersCount is excluded from content comparison.

Expected root updatedAt/lastRevisedAt and each question updatedAt are excluded only from cross-save matching because the service regenerates them. They remain in before/after snapshots, content revisions, repeated-read stability, no-op detection and pre-effect conflict checks. Other unknown business fields remain required to match. Expected question arrays are sorted by explicit order; option positions are not normalized. Saved journal snapshots are validated without rewriting or migrating their arrays. This narrow tolerance can reconcile a known-ID sent revision by readback but does not weaken pre-save conflict checks or permit unrelated drift. A mismatch still returns QUESTIONNAIRE_READBACK_MISMATCH and preserves the pending task; never resubmit just to force completion.

All baseline/readback records, the creation receipt, outgoing revision DTO and persisted before/after/created identities must belong to the selected numeric channel. Missing or conflicting identity is rejected, not silently stripped. A foreign answer parent cannot supply a valid revision. Older journals lacking the now-required channel identity are not automatically migrated; preserve them for inspection.

QUESTIONNAIRE_COMPLETE includes taskId, taskType questionnaire, phase done, questionnaires and revisions containing qrid/revision pairs. saveAcknowledged is separate from observed completion: known-ID readback can confirm a sent change without its acknowledgement. writesPerformed is false for no-op, true for a saved acknowledgement or recorded upload, and can be null when a sent effect is uncertain. verification.confirmed and fullReadbackVerified apply only to fresh completion; atomicSnapshot, causalityVerified, visitorFormVerified and imageAvailabilityVerified stay false. Pending output is QUESTIONNAIRE_PENDING with checkpoints, requiredAction and possibly lastResult/journalPersistence. An auth/context failure can suppress channel/navigation metadata and retain pending status.

Task recovery

Checkpoint Continuation
prepared Recheck original context/baseline; untouched stages may continue.
Per image: prepared Original apply bytes are required after restart; status/resume do not reconstruct files.
Per image: grant-sent or upload-sent Preserve the journal and inspect; no automatic retry of attempted grant/upload.
Per image: uploaded Reuse the checked durable receipt; no second upload.
save-sent Known qrid permits full readback only; never resend create/revise.
done Immutable historical result on status/replay with confirmed:false; get again for current state.

Use task_status or task_resume with the original taskId and explicit taskType questionnaire. Same-ID apply must keep the original input/revision; dryRun is outside its fingerprint. A conflicting requestId returns REQUEST_ID_CONFLICT. Invalid stored identity/fingerprint/progress returns TASK_STATE_UNVERIFIED without adopting the journal. QUESTIONNAIRE_CONFLICT requires a fresh read before an unsent new operation; it is not permission to replace the ID of an uncertain task.

If creation was sent without a durable returned qrid, QUESTIONNAIRE_CREATE_UNKNOWN requires operator inspection. Do not adopt a similarly titled record or automatically repeat creation. A known-ID mismatch remains pending without resend. Completed journal rejection preserves history. There is no questionnaire DELETE tool; deactivate an unwanted record.

Navigation opens the known editor, or the list until create identity is durable.

Saved record identity

A missing record differs from an existing malformed record. Stored JSON null, false, zero or an empty string is rejected with TASK_STATE_UNVERIFIED by the existing record validator. Apply/dry-run/status/resume must not overwrite it or treat it as a fresh task. Preserve the file for inspection; do not delete/edit it or replace the request ID to bypass the error. Existing valid task recovery and genuinely missing-record behavior remain unchanged.