# messenger_room_create_apply
Create one PAID basic-group room with the original default image, a new access catalog and selected memberships and/or a new individual access product. A purchase-enabled product can become purchasable before the room exists. Catalog and room creation are two separately authorized writes with no transaction or automatic rollback.
Connected source: Follow [preparation and transport requirements](messenger_room_create_get.md).
## Complete input
Require channelCode, requestId (8–80 ASCII letters, digits, underscores or hyphens), expectedRevision (64 lowercase hexadecimal characters from the matching preparation), confirmation:CREATE_BASIC_GROUP_ROOM and change. dryRun is optional and defaults false. Unknown fields are rejected. The host resolves D00003 and the installation; no caller-selected service, raw request, credential or existing catalog/product identity is accepted.
| change field | Requirement |
| --- | --- |
| title | Required string, trimmed, 2–40 characters. |
| description | Required string, trimmed, at most 100 characters; empty is allowed. |
| isPrivate | Required boolean, selecting private/public state. |
| pricingType | Required literal PAID. |
| thumbnail | Required literal default. No URL, local path, inline bytes or custom upload task is accepted. |
| membershipIds | Required array of at most 100 distinct current membership business IDs. Each ID is 1–200 ASCII letters, digits, underscores or hyphens. Empty is allowed only with an individual product. |
| individualProduct | Required complete object below, or null for membership-only access. Existing products cannot be attached through this creation input. |
| acknowledgeInactiveMonetization | Optional boolean, defaults false. Must be true when preparation observed inactive monetization; it does not activate monetization. |
At least one membership or individual product is required. Membership order is normalized; this does not enroll or modify members. An active messenger and current same-context prerequisites are required even for a fresh dry run.
## New individual access product
All product fields are required when individualProduct is non-null:
| Field | Contract |
| --- | --- |
| name | Trimmed string, 2–40 characters. |
| price | Object with currency KRW or USD and amount as a nonnegative decimal string, at most 16 characters and up to two decimal places. Must use the verified channel currency and limits below. |
| originalPrice | Same money object or null; null uses the selling price. A supplied original price must satisfy the same limits and be at least the selling price. |
| availableDays | 1, 3, 7, 15, 30, 60, 90, 180, 365, or null. |
| purchaseAvailable | Boolean; true can enable purchase of the new product during catalog creation. |
| purchaseMethods | CASH_ONLY or CASH_AND_CP. The latter requires existing verified point branding. |
Use the returned priceLimits: ordinary KRW minimum 300, maximum 100,000,000 and step 100, with source-specific channel minimum overrides; USD minimum 5, maximum 100,000 and whole-dollar steps. Decimal syntax does not permit fractional USD prices in this workflow. The original USD transport multiplier is 1,000. No currency conversion or new branded-point setup occurs. The generated product fixes isDeactivated:false and both sale dates to null; custom scheduling is unavailable.
## Save and readback
A fresh dry run returns PLAN_READY, catalog/room payload plans and writesPerformed:false. Catalog/product/room IDs must come from future receipts. It creates no journal, requests no write authorization and sends no creation. A dry run for an existing request is historical inspection, not fresh validation.
Real execution checkpoints prepared → catalog-sent → catalog-confirmed → room-sent → done. Before each write, current prerequisites are rechecked and the host authorizes the exact one-use payload. Catalog creation retains only the returned ccid and optional templateId, verifies that exact catalog, selected membership identities and product configuration, then creates the room using those identities. The returned room must match the channel, installation, GROUP/PAID state, metadata, default image and access links. Final completion requires stable readback of prerequisites, catalog and the exact returned room.
MESSENGER_CREATION_COMPLETE includes taskId, taskType:messenger-room-create, roomUuid, catalogId, nullable templateId, phase:done and storedReadback:true. Fresh completion has verification.currentReadback:true. MESSENGER_CREATION_PENDING and diagnostic lastError retain partial progress. writesPerformed can be null when a request was sent without a saved receipt; it must not be interpreted as no effect. Journal persistence uncertainty is separately reported as MESSENGER_CREATION_JOURNAL_UNCERTAIN. Readback does not prove atomicity, member access or an actual purchase.
## Recovery and limits
Use [task_status](publ_task_status.md) and [task_resume](publ_task_resume.md) with taskType:messenger-room-create and the original task ID. Status is historical. Shared resume is observation-only and sends no business writes, including at prepared and catalog-confirmed. It can reconcile attempted work with saved identities. To authorize an unattempted next stage, repeat the identical original apply after current checks. Do not change its inputs, revision or requestId to bypass an unfinished task.
Missing catalog identity (MESSENGER_CATALOG_UNKNOWN) or room identity (MESSENGER_ROOM_UNKNOWN) stays unresolved: no title search, receipt guessing, replacement creation or uncertain POST replay. An equivalent unfinished intent is guarded across connections sharing the state store. Changing the plan is not recovery, and this does not provide distributed locking across separate stores or console writers. Preserve corrupt journals, claims and crash locks for inspection.
Completed replay/status remains historical with current verification false. Only validated preparation/plans can identify the exact creation screen, and only fresh verified completion can identify the returned room. Pending, incomplete, foreign and historical results have no current room success link. Use the exact returned navigation; do not construct a destination to imply success.
Orphan catalogs/products can remain after interruption. No deletion, compensation, identity-preserving undo or cleanup is provided. FREE/direct/autonomous rooms, custom thumbnails, member enrollment, purchases, refunds, notifications and message sending are outside this connected flow. Other Messaging contracts remain unregistered.
## Inputs
| Field | Required here | Contract |
| --- | --- | --- |
| `confirmation` | Yes | `CREATE_BASIC_GROUP_ROOM` |
| `change` | Yes | object |
| `change.title` | Yes | string; min length 2; max length 40 |
| `change.description` | Yes | string; max length 100 |
| `change.isPrivate` | Yes | boolean |
| `change.pricingType` | Yes | `PAID` |
| `change.thumbnail` | Yes | `default` or object; default (the original image) or {uploadTaskId} of a completed messenger_room_thumbnail_apply made without roomUuid. |
| `change.thumbnail.uploadTaskId` | Yes | string; pattern `^[A-Za-z0-9_-]{8,80}$` |
| `change.membershipIds` | Yes | array; items: string; pattern `^[A-Za-z0-9_-]{1,200}$`; max items 100 |
| `change.individualProduct` | No | object or null; default `null`; The room's individual product; omit or null when the room is sold only through memberships. A membership or an individual product is required. |
| `change.individualProduct.name` | Yes | string; min length 2; max length 40 |
| `change.individualProduct.price` | Yes | object |
| `change.individualProduct.price.currency` | No | `KRW`, `USD`; Omit to use the verified channel base currency already read by the host. An explicit currency only asserts that it matches; it never changes the currency or supplies an unknown default. |
| `change.individualProduct.price.amount` | Yes | string; max length 16; pattern `^(?:0\|[1-9]\d*)(?:\.\d{1,2})?$` |
| `change.individualProduct.originalPrice` | Yes | object or null |
| `change.individualProduct.originalPrice.currency` | No | `KRW`, `USD`; Omit to use the verified channel base currency already read by the host. An explicit currency only asserts that it matches; it never changes the currency or supplies an unknown default. |
| `change.individualProduct.originalPrice.amount` | Yes | string; max length 16; pattern `^(?:0\|[1-9]\d*)(?:\.\d{1,2})?$` |
| `change.individualProduct.availableDays` | Yes | `1` or `3` or `7` or `15` or `30` or `60` or `90` or `180` or `365` or null |
| `change.individualProduct.purchaseAvailable` | Yes | boolean |
| `change.individualProduct.purchaseMethods` | Yes | `CASH_ONLY`, `CASH_AND_CP` |
| `change.acknowledgeInactiveMonetization` | No | boolean; default `false` |
| `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. |
## Input example
Illustrative membership-only dry run. Replace the membership ID with a current candidate and the all-zero revision with the matching preparation result. If monetization is inactive, obtain the user's intended continuation and set the acknowledgement accordingly.
```json
{
"channelCode": "selected-channel",
"requestId": "messenger-create-001",
"expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
"confirmation": "CREATE_BASIC_GROUP_ROOM",
"dryRun": true,
"change": {
"title": "Member discussion",
"description": "A group for current members",
"isPrivate": true,
"pricingType": "PAID",
"thumbnail": "default",
"membershipIds": ["observed-membership-id"],
"individualProduct": null,
"acknowledgeInactiveMonetization": false
}
}
```