channel_create — plan and create a site
New default-image tasks also use a durable completion refresh checkpoint; status exposes an uncertain refresh without resending it.
Current HTTP legacy icon handling rejects iconAssetId before planning or writes, including dry runs. See the legacy-icon preflight and saved-task guidance. New original-image tasks use iconFile; do not rewrite existing task inputs.
Creation response and unknown-outcome behavior are tightened by the current response correction. Unreadable write acknowledgements are not treated as unsent work.
Current file-template behavior supersedes the historical uploader limitation below: see the file-template handoff correction. It is a console handoff, not an implemented automatic import.
The current title rule and task recovery guidance explain emoji and the broader advertised JSON Schema envelope.
See the current correction and older-server guidance before preparing new inputs; keep existing task inputs unchanged during recovery.
Submit the new site's title, design, apps, transaction currency and optional original icon as one workflow. It validates current choices, creates the channel, refreshes credentials, and reads channel detail. To rename an existing site, use channel_settings_apply instead. Read channel_creation_options for the intended category first.
Input
| Field | Type | Required | Default and constraints |
|---|---|---|---|
requestId |
string | Yes | 8–80 ASCII letters, digits, underscores, or hyphens: ^[A-Za-z0-9_-]{8,80}$. Reuse it for this same operation. |
siteTitle |
string | Yes | Trimmed before validation; length 4–20 under the registered string validator (Unicode code points in the captured Zod runtime). It is the site title. |
category |
enum string | Yes | HOMEPAGE, LECTURE, CONTENTS, EVENT, COUNSEL, COMMUNITY, or CUSTOM_SERVICE. |
design |
object | Yes | One of the three forms below. |
baseCurrency |
enum string | No | KRW or USD, subject to the platform currency rules. |
appCodes |
string array | No | Each matches ^[A-Za-z0-9_]+$. Omission and an empty array have different meanings. Duplicate selections are rejected during planning. |
acceptNoApps |
boolean | No | false; confirms intentional creation without apps where required. |
iconAssetId |
string | No | Legacy nonempty staged-asset identifier; the HTTP adapter does not implement this path. Do not mix with iconFile. |
iconFile |
object | No | Strict {filename,base64} for an original PNG/JPEG; blank/catalog designs only. See the file contract below. |
dryRun |
boolean | No | false; true returns a plan without creation. |
design.kind |
Other fields | Meaning |
|---|---|---|
blank |
None | Blank design with selected/recommended apps. |
catalog |
Required nonempty templateCode |
Current template returned for this category. Its installed apps are fixed. |
file |
Required nonempty assetId |
Legacy file-template branch. HTTP returns FILE_TEMPLATE_CONSOLE_REQUIRED before planning or writes, even for dry runs; use the exact returned creation-screen link with the original file. |
The top-level object and all design variants are strict. Additional fields and null are rejected. Use siteTitle, not title; do not submit an HTTP request body, password, token, or arbitrary URL. The runtime trims the title before fingerprinting; JSON Schema itself does not encode this transform.
App and currency planning
| Selection | Planning behavior |
|---|---|
Blank, omitted appCodes |
Use the intersection of category recommendations and current available apps. Recommendations may be unavailable, leaving no apps. |
Blank, explicit appCodes:[] |
Request no apps; acceptNoApps:true is required. |
Catalog, omitted appCodes |
Use the template's fixed configuration, after checking every included app is an allowed candidate. |
Catalog, explicit appCodes |
Must equal the template configuration; comparison ignores order, not duplicates or membership changes. Empty templates still need acceptNoApps:true. |
| File | Omit appCodes or pass []. Nonempty apps are rejected; acceptNoApps is not required for this branch. |
Selected apps must be released/visible and pass the options filter. Planning takes each app's first default FREE pricing model, requires its code to match the app code, and checks all three fees in the selected currency: installation, monthly base, and metered unit. Each must explicitly carry that currency and a zero amount string. A FREE label alone is insufficient. Missing, paid, or unverifiable costs require human console creation; this tool submits no payment.
A platform object fixes currency to its baseCurrency, or to KRW when that field is absent. If platform:null, use the supplied currency or default to KRW. The current account's platform rule takes precedence over a caller's preference.
Examples
The following is an illustrative blank-design plan. Omitted apps use current recommendations; inspect the actual plan and any no-app confirmation result before executing.
{
"requestId":"example-site-create-001",
"siteTitle":"Example site",
"category":"HOMEPAGE",
"design":{"kind":"blank"},
"dryRun":true
}
For a catalog design, use the returned template identifier and normally omit appCodes:
{
"requestId":"example-site-create-002",
"siteTitle":"Catalog example",
"category":"HOMEPAGE",
"design":{"kind":"catalog","templateCode":"template-code-from-options"},
"dryRun":true
}
The template code is a placeholder, not a known current template. Neither example is a recorded execution. After inspecting a valid plan, submit the same request ID and business inputs with only dryRun changed to false. Select the intended apps and currency from current options, rather than assuming the examples suit the account.
Plan and request mapping
The workflow maps ordinary business inputs to its request body:
| Input or choice | Planned HTTP body |
|---|---|
siteTitle |
title; no independent title input. |
| New owner display profile | profile.nickname:Owner and the built-in default profile image. |
| Images/description | Built-in default icon and thumbnail, plus empty description body. Inline iconFile replaces only iconImageSrc with the acknowledged upload location; legacy asset IDs remain unavailable. |
| Blank apps | pAppCodes contains each selected default pricing model as code:ppmid. |
| Catalog/file apps | pAppCodes:[]; a catalog's apps are applied through its template. |
| Category | onboardingChannelServiceCategoryCode. |
| Blank/catalog/file design | onboardingChannelTemplateCode is CUSTOM_SERVICE, the selected template code, or CUSTOM_SERVICE_WITH_TEMPLATE, respectively. |
| File definition | Historical source mapping uses an uploaded definition in givenDefinition. The HTTP workflow hands new and unsent file-template work to the console; it does not upload or fabricate a definition. |
Before a real creation or prepared-job resume, current options are reread and the derived plan is compared with the saved plan. This does not reserve options or verify server state atomically. The comparison covers the derived body, not every catalog/pricing field that could change without changing that body.
The HTTP path is POST /seller/api/v1/channels with the account bearer, then POST /seller/api/v2/refresh with the refresh token and no account bearer, then GET /seller/api/v1/channels/{channelCode} with the selected channel bearer. The creation receipt must identify the new channel. The HTTP adapter normalizes a missing/empty channel code from primitiveInvitationCode when available.
Inline icon contract
iconFile.filename is a PNG/JPG/JPEG basename, 1–240 characters, without paths, drive/URL prefixes, colon or controls. Extension matching is case-insensitive at runtime; use lowercase to also satisfy the exported regex, which omits its flag. base64 is canonical original-file base64, 4–1,333,336 characters, without whitespace or a data-URL prefix. Decoded bytes must be nonempty and at most 1,000,000 decimal bytes. The PNG/JPEG structure must match the extension. No resizing, rendering, remote fetching or image-content rewriting occurs. This is separate from the larger marketing image limit.
Do not combine iconFile with iconAssetId or design.kind:file: the workflow returns CREATION_ICON_INPUT_CONFLICT before account access. This cross-field rule and byte validation exceed exported JSON Schema. Invalid files return INVALID_CHANNEL_ICON. The host must configure its resource gateway, bucket and region even for a new icon dry run; URLs and credentials are not tool inputs. Legacy icon IDs return UPLOAD_NOT_CONNECTED before option reads, planning or writes, even for dry runs; the returned link targets the creation screen. Existing prepared journals and any saved location are preserved, not migrated to iconFile. File-template plans and unsent tasks return FILE_TEMPLATE_CONSOLE_REQUIRED without an upload or create. Owner profile-image uploads are outside this creation input.
Before a new icon task, verified account connection, seller, main profile and role bind the operation. New dry runs read options and validate file/configuration but issue no grant, PUT, creation, refresh or job. Real execution issues an account-scoped POST /seller/api/v1/credentials to the resource gateway, without channel/consumer headers, then uploads the unchanged bytes with a checksum. It validates the receipt and supplies its exact location to the composite channel POST. Creation/grant accept 200 or 201 data envelopes; final channel GET requires 200/data, bounded to 2 MiB. Options and owner context are rechecked before creation. The created channel detail uses that channel's bearer after account refresh.
{"requestId":"example-icon-create-001","siteTitle":"Example icon site","category":"CUSTOM_SERVICE","design":{"kind":"blank"},"appCodes":[],"acceptNoApps":true,"iconFile":{"filename":"icon.png","base64":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aDWQAAAAASUVORK5CYII="},"dryRun":true}
This illustrative tiny file is a schema/parser example, not a recorded upload or recommended artwork. Use the user's original file. A successful upload can remain unused if later options, pricing, context or creation checks fail; no object deletion or rollback is performed.
Inputs
| Field | Required here | Contract |
|---|---|---|
siteTitle |
Yes | string; min length 2; max length 20; Site title, 4–20 UTF-16 code units after trimming. Emoji can occupy two units. The advertised 2–20 code-point envelope is necessary but not sufficient; execution enforces the screen limit. |
category |
Yes | HOMEPAGE, LECTURE, CONTENTS, EVENT, COUNSEL, COMMUNITY, CUSTOM_SERVICE |
baseCurrency |
No | KRW, USD |
design |
Yes | one of: blank, catalog (by kind) |
design.templateCode |
Yes | When design.kind is catalog: string; min length 1; A template code from channel_creation_options. |
appCodes |
No | array; items: string; pattern ^[A-Za-z0-9_]+$ |
acceptNoApps |
No | boolean; default false |
iconFile |
No | one of: local-file, more-parts, complete, cancel (by kind) |
iconFile.filename |
Yes | When iconFile.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. |
iconFile.byteLength |
Yes | When iconFile.kind is local-file: integer; greater than 0; The exact file size in bytes (for example from wc -c < FILE or stat). |
iconFile.sha256 |
No | When iconFile.kind is local-file: string; pattern ^[0-9a-f]{64}$ |
iconFile.uploadId |
Yes | When iconFile.kind is more-parts: string; pattern ^upl_[A-Za-z0-9_-]{22}$ |
iconFile.fromPart |
Yes | When iconFile.kind is more-parts: integer; minimum 1; maximum 10000 |
iconFile.uploadId |
Yes | When iconFile.kind is complete: string; pattern ^upl_[A-Za-z0-9_-]{22}$ |
iconFile.parts |
Yes | When iconFile.kind is complete: array; min items 1; max items 10000 |
iconFile.parts[].partNumber |
Yes | When iconFile.kind is complete: integer; minimum 1; maximum 10000 |
iconFile.parts[].etag |
Yes | When iconFile.kind is complete: string; min length 1; max length 200 |
iconFile.measured |
No | When iconFile.kind is complete: object; What the video measures on this computer, read with measureCommand. |
iconFile.measured.durationSeconds |
Yes | When iconFile.kind is complete: number; maximum 1000000; greater than 0; Video duration in seconds (ffprobe format.duration). |
iconFile.measured.frameRate |
Yes | When iconFile.kind is complete: number; maximum 1000; greater than 0; Frames per second (ffprobe avg_frame_rate, for example 30000/1001 = 29.97). |
iconFile.measured.width |
Yes | When iconFile.kind is complete: integer; maximum 100000; greater than 0 |
iconFile.measured.height |
Yes | When iconFile.kind is complete: integer; maximum 100000; greater than 0 |
iconFile.measured.frameRateMode |
No | When iconFile.kind is complete: CFR, VFR |
iconFile.measured.minFrameRate |
No | When iconFile.kind is complete: number; maximum 1000; greater than 0 |
iconFile.measured.maxFrameRate |
No | When iconFile.kind is complete: number; maximum 1000; greater than 0 |
iconFile.uploadId |
Yes | When iconFile.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. |
irreversibleConfirmed |
No | true; true only after the person confirmed again, when the preview has requiresReconfirmation: the action cannot be undone. |
Results and completion
| Path | Payload |
|---|---|
| New dry run | status:success, code:PLAN_READY, taskType:channel-create, taskId, environment, created:false, planned body, steps, and requiredAssets. |
| Existing job dry run | PLAN_READY with the same identity/environment, created:false, stored body, phase, existingPhase and historical replay fields; no fresh options read or completion verification. See saved-plan replay below. |
| Completed creation | status:success, code:CHANNEL_CREATED, taskType:channel-create, taskId, environment, channel, and verification. |
| Failure or human action | Workflow-specific status/code/message, with optional outcome, environment, task identity, phase, and known channel. Input/protocol failures can have a different shape. |
A new dry run does not persist a job, despite returning taskId. Its steps are validate, upload_if_needed, create, refresh, and verify. requiredAssets merely lists supplied asset IDs; it does not validate them. An existing job's created:false dry-run field means the dry-run call performs no creation, not that the stored job has never created a channel.
The completed channel contains id, channelCode, title, baseCurrency, optional currentPlan, and the verified iconImageSrc for inline-icon completion. verification.confirmed:true with method:channel_detail confirms the detail ID/code against the receipt and the title/currency against the plan. It does not confirm installed apps, public launch, domain availability, visitor rendering, or payment eligibility. Fresh non-demo completion can return the observed new channel's console home through the shared finalizer. Historical completion suppresses current navigation; neither is a visitor URL.
Saved identity, effects, and recovery
Real execution writes the private job and, after successful refresh, the credential file. The task ID equals the request ID. The fingerprint uses parsed inputs with dryRun:false; input defaults/trim are normalized, while app order and omitted-versus-explicit business fields can still affect identity. Reusing a saved ID with different inputs or connection returns TASK_CONTEXT_CHANGED.
Call task_status with the original ID and taskType:channel-create to inspect progress. To continue the original operation, call task_resume with that same pair:
| Phase | Meaning and recovery |
|---|---|
prepared |
Job exists but creation has not been sent, or a definite not_sent creation failure restored this phase. Revalidate the saved plan before remaining upload/creation steps. |
creating |
Persisted before the creation POST. The receipt may be lost. Resume returns CREATE_OUTCOME_UNKNOWN and does not repeat creation. |
created |
A channel receipt was saved. New tasks follow the saved refresh checkpoint and then verify detail; they never create again. An uncertain refresh is not redispatched. |
done |
Return the historical saved completion; use a fresh channel read for current state. |
failed |
A definitely rejected creation is stored as failed. Resume returns the saved failure and performs no new creation. |
Historical default-image tasks without a versioned checkpoint retain their prior format. An explicitly recorded unknown completion now stops without refresh; other marker-free tasks still require inspection of their earlier recovery history. New default-image tasks record refresh pending/sent/done; after an acknowledged refresh, only detail verification is retried. task_status returns completion.credentialRefresh as pending, outcome_unknown or acknowledged. Inline-icon jobs retain their existing separate upload/refresh journal.
Inline-icon jobs store file metadata/hash and owner/plan bindings, never the file bytes or temporary upload credentials. The fingerprint uses metadata, including filename and SHA-256; reusing the ID with different bytes is rejected. Status validates the journal/owner without advancing effects. Recovery adds these boundaries:
| Inline-icon checkpoint | Next action |
|---|---|
| upload prepared | Resume without bytes returns action_required / ICON_FILE_REQUIRED. Recall channel_create with identical requestId, original inputs and original file bytes. |
| grant-sent / upload-sent | ICON_UPLOAD_OUTCOME_UNKNOWN; preserve the task. Neither grant nor PUT is repeated. |
| uploaded, creation known not sent | Retain the acknowledged object and revalidate options before the original creation; no second upload. |
| creating | CREATE_OUTCOME_UNKNOWN; never recreate automatically. |
| refresh pending | Checkpoint sent before account refresh. |
| refresh sent | CREATION_REFRESH_OUTCOME_UNKNOWN; no repeated refresh. Preserve the task for connection inspection/repair. |
| refresh done, detail failed | Retry exact channel readback without upload, creation or refresh. |
| done | Historical result, verification.confirmed:false and writesPerformedThisCall:false. Use its channels_list reread recipe and select the observed channel for current state. |
Fresh icon completion additionally requires exact uploaded location equality and returns iconLocationConfirmed:true, publicRenderingVerified:false. Invalid/inconsistent journals return CHANNEL_CREATION_STATE_INVALID without rewriting previous evidence. Do not edit old jobs to opt into these checkpoints.
If only a new dry run ran, TASK_NOT_FOUND is expected. A successful creation can precede a failed refresh/readback, so an error does not necessarily mean nothing was created. Keep the original ID and known channel; do not delete job state, change its binding, or create under a new ID to bypass an uncertain result. There is no automatic channel deletion/rollback or global server idempotency guarantee. Local task/connection locks do not automatically expire; an operator must inspect abandoned locks before repair.
In hosted mode creation, options, and channel-create recovery are account operations. Subsequent channel work requires a separately authorized selected-channel resource.
Failures and next action
| Code | Meaning and response |
|---|---|
TEMPLATE_UNAVAILABLE |
The selected template is not CURRENT in this category's returned page. Read current options; do not invent a replacement. |
TEMPLATE_APPS_READONLY |
An explicit app array changes the catalog template configuration. For a new plan, omit the override; do not rewrite an existing job's input. |
DUPLICATE_APP, FILE_TEMPLATE_APP_CONFLICT, APP_UNAVAILABLE |
Correct a new selection according to current options and design rules. |
NO_APPS_CONFIRMATION_REQUIRED |
Human-action result: confirm that creation without apps is intended before preparing that input. |
DEFAULT_FREE_PLAN_MISSING |
A selected app has no default FREE model. |
CHANNEL_CREATION_PAYMENT_REVIEW_REQUIRED |
Human-action result when costs or all template apps cannot be verified. Before upload it reports writesPerformed:false; after an acknowledged icon upload it instead reports uploadedIconRetained:true and channelCreationPerformed:false without claiming zero effects. Use the non-demo console handoff for human creation. |
PLATFORM_CURRENCY_LOCKED |
The caller's currency conflicts with the account platform rule. |
OPTIONS_CHANGED |
The saved derived plan no longer matches current options. Inspect the original task and current choices. |
UPLOAD_NOT_CONNECTED |
Human-action result before creation: the requested creation upload path is unavailable. |
CREATE_RESPONSE_UNVERIFIED, CREATE_OUTCOME_UNKNOWN |
A usable creation receipt or outcome is unavailable. Preserve the original task and request operator inspection; do not guess a channel from a matching title. |
REFRESH_CONTRACT_UNVERIFIED, CHANNEL_CREDENTIAL_MISSING |
Creation can already be complete at the service; inspect the saved phase and original channel before repairing the connection. |
VERIFICATION_MISMATCH |
Detail ID/code/title/currency, or the inline icon location, does not match the expected creation. Do not report verified completion. |
TASK_CONTEXT_CHANGED, CONNECTION_CHANGED |
Saved input or connection does not match. Do not adopt the job under another account. |
Authentication, HTTP, private-storage, and lock failures follow common results. Plan errors must not be resolved by overwriting saved tasks.
Implementation: src/contracts.ts::inputSchema/planChannel, src/workflow.ts::ChannelWorkflow, src/publ-http.ts, src/papp-pricing.ts, and src/state.ts.
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: channels_list with markChannelAs:"RUNNING" is account-scoped and does not guess a channel from its title. Saved body and existingPhase remain; created:false means this dry-run call created nothing. Prepared input-policy checks, journal/account/owner validation and original file input matching remain in force. Saved history does not require new options or certify current upload readiness.
Saved record identity
Apply/dry-run replay and task status/resume bind both the saved ID and saved input
requestId to the requested task ID. An intact record stored under another lookup
key is also refused with TASK_STATE_UNVERIFIED, before business reads or effects.
Keep both records for inspection; do not rename/edit them, use the embedded ID or
create a replacement task to bypass refusal. Matching tasks keep their existing
validation and recovery rules. Connection/authorization checks may still run;
this guard is not a complete record schema or current-state verification.