membership_product_create
Create one product under an existing membership from the complete source wizard choices. This configures a sale or subscription offer; it does not purchase it, charge funds, issue serial keys or enroll a member.
Observe the parent membership
Use memberships_get detail and copy its revision.
This is the membership revision, not the product-list page revision. Choose the
parent by its mid, not its numeric row ID. The selected-channel owner or a
delegate with MANAGE_MONETIZATION is required.
{"channelCode":"selected-channel-code","view":{"kind":"detail","membershipMid":"returned-membership-mid"}}
Compose the wizard
{
"requestId":"product-create-001",
"channelCode":"selected-channel-code",
"membershipMid":"returned-membership-mid",
"expectedMembershipRevision":"0000000000000000000000000000000000000000000000000000000000000000",
"title":"Monthly access","alias":"One month access",
"availablePurchaseMethodsType":"CASH_ONLY",
"offer":{"kind":"paid-once","periodInDays":30,"feeAmount":"5000"},
"dryRun":true
}
Replace the revision with the current observed value. Title and displayed alias are trimmed and checked against the active source 4–20 UTF-16-unit bounds. Two supplementary-plane emoji occupy four units. The older generic form defaults use different limits; the active screen controls determine this contract.
| offer.kind | periodInDays | feeAmount |
|---|---|---|
| paid-once | 30,90,180,365 or null for unlimited | Required |
| subscription | 30,90,180,365 | Required; period maps to the recurring type |
| free | 1,3,7,14,30 | Omit |
| coupon-paid | 30,90,180,365 or null | Required |
| coupon-free | 1,3,7,14,30,90,120,180,365 or null, subject to eligibility | Omit |
There is no ordinary FREE_INFINITE choice in the active wizard. A finite offer sends expiryPeriodInDays; a recurring offer encodes its period in its type. The bridge composes the same type/title/alias/purchase-method/fee/period source body instead of exposing raw API fields or step-by-step Next calls.
Amounts are decimal strings without grouping and use the observed channel base currency. KRW accepts 300–10,000,000 in 100-unit steps; ordinary USD accepts 5–10,000 in whole-dollar units after the source formatting check. Exact source channel exceptions change minima; the two source USD exception channels allow cents. Creation intentionally follows its active legacy validation, while extension pricing follows the newer currency policy and ordinarily allows USD cents. The body formats USD to two decimals and KRW to an integer. Other base currencies are outside the current membership contract. Free offers omit fee; readback must confirm zero in the parent currency.
CASH_ONLY is the default. Only ordinary paid-once permits CASH_AND_CP; fresh valid Channel Point branding is required during preparation and immediately before submission. No branding is created, and no points are issued or charged.
Coupon offers require the source coupon-capable plans: NORMAL_BUSINESS, NORMAL_PRO, NORMAL_FROM_ENTERPRISE, ENTERPRISE_TRIAL, ENTERPRISE_ENTERPRISE, PARTNER_TRIAL, PARTNER_PARTNER or INTERNAL_INTERNAL. Other/future plans are not assumed eligible. Ordinary free/paid/recurring creation does not gain an invented selling-plan or monetization-activation gate.
Production coupon-free periods above seven days or unlimited require current source manual-action permission for the selected channel or authenticated operator. The runtime reads its configured public primary/fallback resource with no credentials, identity query or channel header; only the derived boolean enters the task. Missing/unavailable policy is not permission. Nonproduction unlimited free coupons remain unavailable for FREE_/NORMAL_ plans. Environment comes from the registered API environment, never caller arguments. There is no bypass flag.
Apply, verify and recover
A fresh dry run returns PLAN_READY, body and derived policy without a POST or new task. Submit the same values with dryRun false to create. The parent revision, operator, channel and relevant permission/branding are rechecked before one POST. A validated receipt ID is saved, followed by an independent read of that exact ID under the same parent route. Requested title/alias/type/fee/explicit period and purchase methods must agree; the parent metadata and access associations must be preserved. Equivalent decimal trailing zeros do not change an amount. The source receipt's observed selling state is returned, not silently replaced or activated.
MEMBERSHIP_PRODUCT_CREATED confirms that bounded readback. The result includes subscriptionProduct, the exact created ID, taskId and taskType membership-product-create. This does not prove checkout, visitor access, causal ownership or an atomic snapshot. Benefits and installed-feature association come from the existing parent; attaching individual content has its own workflow.
Keep the requestId. task_status reads its saved progress. task_resume only reads: prepared work needs the identical original create call, sent creation is never repeated, and a missing receipt ID remains MEMBERSHIP_PRODUCT_CREATE_ID_UNRESOLVED. Never adopt a same-title/alias/price row or issue another create to bypass unknown outcome. A known receipt can recover after a temporary read outage. Completed replays are historical, not a fresh current product check.
One console destination opens this membership's creation wizard for the plan or the exact created product editor after confirmation. Use the returned link. Source has no product delete/reset operation. Suspending selling with membership_product_apply retains the new record and is not an undo of creation. Existing base title/price/type/period remain locked; only source-supported alias, purchase methods, selling state and extension settings are editable through that method.
Inputs
| Field | Required here | Contract |
|---|---|---|
membershipMid |
Yes | string; min length 1; max length 512; Copy membership.mid from the selected memberships_get detail, not a channel code, numeric membership ID or member/profile ID. |
title |
Yes | string; min length 2; max length 20 |
alias |
Yes | string; min length 2; max length 20 |
availablePurchaseMethodsType |
No | CASH_ONLY, CASH_AND_CP; default CASH_ONLY |
offer |
Yes | one of: paid-once, subscription, free, coupon-paid, coupon-free (by kind) |
offer.periodInDays |
Yes | When offer.kind is paid-once: 30 or 90 or 180 or 365 or null |
offer.feeAmount |
Yes | When offer.kind is paid-once: string; pattern ^(?:0|[1-9]\d{0,7})(?:\.\d{1,2})?$ |
offer.periodInDays |
Yes | When offer.kind is subscription: 30 or 90 or 180 or 365 |
offer.feeAmount |
Yes | When offer.kind is subscription: string; pattern ^(?:0|[1-9]\d{0,7})(?:\.\d{1,2})?$ |
offer.periodInDays |
Yes | When offer.kind is free: 1 or 3 or 7 or 14 or 30 |
offer.periodInDays |
Yes | When offer.kind is coupon-paid: 30 or 90 or 180 or 365 or null |
offer.feeAmount |
Yes | When offer.kind is coupon-paid: string; pattern ^(?:0|[1-9]\d{0,7})(?:\.\d{1,2})?$ |
offer.periodInDays |
Yes | When offer.kind is coupon-free: 1 or 3 or 7 or 14 or 30 or 90 or 120 or 180 or 365 or null |
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. |