publ betaReference (MCP guide)
Open publ console

ticket_operation_apply

# ticket_operation_apply

Apply the exact E00003 operation prepared by
[ticket_operations_get](ticket_operations_get.md). Keep channel, event, hall,
schedule and every operation field unchanged; copy the preparation revision into
`expectedRevision` and choose one stable `requestId`. `dryRun:true` previews
without saving. The default is false.

Parking changes eligible ONLINE seats to PARKING. Parking metadata changes only
the type/memo on eligible parked seats. Release returns eligible parked seats to
ONLINE at their observed common tier and unchanged prices. Single and bulk
variants use the same rules; bulk accepts 1–100 unique IDs. Occupied selections
stop the whole request before dispatch. Already-satisfied selections are omitted,
and an all-satisfied request is a noop. Price alone does not imply occupancy.

Price uses one UPDATE_OVERRIDDEN_PRICES dispatch for changed selected seats. It retains other overrides, occupancy, ticket counts and original schedule policies. An ONLINE seat stores overrides on its slot; a PARKING seat stores them on its metadata. Both are verified against stable readback. Returning to an old amount needs a separately prepared price change.

The server marks the operation sent before one source dispatch and then reads
back stable schedule and sheet observations. Completion requires every requested
change, correct count deltas and preserved unrelated seats, unselected prices and metadata.
A changed buyer assignment, partial effect or collateral change stays pending.
This does not provide an atomic database transaction or prove causality.

Deletion requires DELETE_SCHEDULE and every ticket eligible. Completion requires
an explicit same-identity DELETED detail, with retained schedule metadata/counts;
a 404 or unavailable detail stays pending. There is no automatic deletion undo.
Unparking can restore availability but creates new slot identities and does not
erase audit history or restore old slots. Actual restoration must be separately
prepared and verified when appropriate.

For `pending`, keep the original requestId. `task_resume` with
`taskType:"commerce-ticket-operation"` and that taskId only observes the sent
operation. It never issues the dispatch again. Prepared work requires the exact
original apply. Do not create another requestId to retry an uncertain write.
`task_status` and completed replays are historical; get again for current state.

A verified current result returns one exact schedule ticket-control-room link.
Deletion returns the surviving schedule list, whose current filters may differ.
Historical or unconfirmed results do not supply a current destination. A link or
dry run is not evidence of a successful change.

No order, payment, refund, buyer assignment, ticket printing, issuance, redemption or notification is executed.

## Inputs and plan

| Field | Required here | Contract |
| --- | --- | --- |
| `channelCode` | Yes | string; min length 1; max length 512; The exact channelCode selected through channel discovery. Do not supply a URL, channel numeric ID, account ID or credentials. |
| `pAppCode` | Yes | `E00003` |
| `eventId` | Yes | string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `hallId` | Yes | string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `scheduleId` | Yes | string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `operation` | Yes | one of: `price`, `parkMany`, `unparkMany`, `parkingMetaMany`, `park`, `unpark`, `parkingMeta`, `deleteSchedule`, `purchase`, `tier` (by `kind`) |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `price`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.eventPolicyTierPriceId` | Yes | When `operation.kind` is `price`: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `operation.payment` | Yes | When `operation.kind` is `price`: one of: `free`, `paid` (by `kind`) |
| `operation.payment.amount` | Yes | When `operation.kind` is `price` and `operation.payment.kind` is `paid`: string; pattern `^(0\|[1-9]\d{0,9})(\.\d{1,2})?$` |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `parkMany`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.parking` | Yes | When `operation.kind` is `parkMany`: object |
| `operation.parking.type` | Yes | When `operation.kind` is `parkMany`: `LOCATION`, `EXTERNAL`, `DEACTIVATED`, `ETC` |
| `operation.parking.memo` | Yes | When `operation.kind` is `parkMany`: string; max length 200 |
| `operation.confirmation` | Yes | When `operation.kind` is `parkMany`: `CHANGE_TICKET_AVAILABILITY` |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `unparkMany`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.confirmation` | Yes | When `operation.kind` is `unparkMany`: `CHANGE_TICKET_AVAILABILITY` |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `parkingMetaMany`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.parking` | Yes | When `operation.kind` is `parkingMetaMany`: object |
| `operation.parking.type` | Yes | When `operation.kind` is `parkingMetaMany`: `LOCATION`, `EXTERNAL`, `DEACTIVATED`, `ETC` |
| `operation.parking.memo` | Yes | When `operation.kind` is `parkingMetaMany`: string; max length 200 |
| `operation.sheetItemId` | Yes | When `operation.kind` is `park`: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `operation.parking` | Yes | When `operation.kind` is `park`: object |
| `operation.parking.type` | Yes | When `operation.kind` is `park`: `LOCATION`, `EXTERNAL`, `DEACTIVATED`, `ETC` |
| `operation.parking.memo` | Yes | When `operation.kind` is `park`: string; max length 200 |
| `operation.confirmation` | Yes | When `operation.kind` is `park`: `CHANGE_TICKET_AVAILABILITY` |
| `operation.sheetItemId` | Yes | When `operation.kind` is `unpark`: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `operation.confirmation` | Yes | When `operation.kind` is `unpark`: `CHANGE_TICKET_AVAILABILITY` |
| `operation.sheetItemId` | Yes | When `operation.kind` is `parkingMeta`: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `operation.parking` | Yes | When `operation.kind` is `parkingMeta`: object |
| `operation.parking.type` | Yes | When `operation.kind` is `parkingMeta`: `LOCATION`, `EXTERNAL`, `DEACTIVATED`, `ETC` |
| `operation.parking.memo` | Yes | When `operation.kind` is `parkingMeta`: string; max length 200 |
| `operation.confirmation` | Yes | When `operation.kind` is `deleteSchedule`: `DELETE_SCHEDULE` |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `purchase`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.orderer` | Yes | When `operation.kind` is `purchase`: object |
| `operation.orderer.name` | Yes | When `operation.kind` is `purchase`: string; min length 1; max length 200 |
| `operation.orderer.phoneCountryCode` | Yes | When `operation.kind` is `purchase`: string |
| `operation.orderer.phoneNumber` | Yes | When `operation.kind` is `purchase`: string; min length 1; max length 12 |
| `operation.orderer.countryCode` | Yes | When `operation.kind` is `purchase`: string |
| `operation.orderer.email` | No | When `operation.kind` is `purchase`: string; pattern `^([a-zA-Z0-9\-\_\.]+)@([a-zA-Z0-9_\-\_\.]+)\.([a-zA-Z]{2,5})$` |
| `operation.reservationId` | Yes | When `operation.kind` is `purchase`: string; min length 1; max length 200 |
| `operation.payment` | Yes | When `operation.kind` is `purchase`: one of: `free`, `paid` (by `kind`) |
| `operation.payment.amount` | Yes | When `operation.kind` is `purchase` and `operation.payment.kind` is `paid`: string; pattern `^(0\|[1-9]\d{0,9})(\.\d{1,2})?$` |
| `operation.parkingInfo` | No | When `operation.kind` is `purchase`: object |
| `operation.parkingInfo.type` | Yes | When `operation.kind` is `purchase`: `LOCATION`, `EXTERNAL`, `DEACTIVATED`, `ETC` |
| `operation.parkingInfo.memo` | Yes | When `operation.kind` is `purchase`: string; max length 200 |
| `operation.confirmation` | Yes | When `operation.kind` is `purchase`: `RECORD_PURCHASE_INFO` |
| `operation.sheetItemIds` | Yes | When `operation.kind` is `tier`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `operation.tierLabelId` | Yes | When `operation.kind` is `tier`: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL. |
| `requestId` | Yes | string; pattern `^[A-Za-z0-9_-]{8,80}$`; Reuse this requestId and the exact original input after interruption. Never change requestId to retry an uncertain write. |
| `expectedRevision` | Yes | string; pattern `^[a-f0-9]{64}$`; Exact revision returned by the matching read for this channel, installed pApp and resource. |
| `dryRun` | No | boolean; default `false` |

Objects are strict; business IDs use 1–160 ASCII letters, digits, underscores or hyphens. Only operation.kind:price accepts a payment amount; caller currency/tier, raw override maps, buyer/assignment data, credentials, consumer, installation override, URL or raw body are not accepted. Current channel permission and bound context must remain valid. The shared host enforces the same 200 UTF-16-unit parking memo limit in both inputs and transport.

These are complete dry-run examples with illustrative IDs and placeholder revisions. Copy each revision from the identical getter operation. Inspect the plan and changed targets, then use dryRun:false only for the intended authorized new change. A changed setting requires a new preparation, not a changed field on an uncertain existing task.

Prepare a single seat hold:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "park",
    "sheetItemId": "sheet-example",
    "parking": {
      "type": "DEACTIVATED",
      "memo": "Maintenance"
    },
    "confirmation": "CHANGE_TICKET_AVAILABILITY"
  },
  "requestId": "ticket-operation-park-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare a single release at its existing tier and prices:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "unpark",
    "sheetItemId": "sheet-example",
    "confirmation": "CHANGE_TICKET_AVAILABILITY"
  },
  "requestId": "ticket-operation-unpark-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare a complete parking type/memo replacement, clearing the memo:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "parkingMeta",
    "sheetItemId": "sheet-example",
    "parking": {
      "type": "LOCATION",
      "memo": ""
    }
  },
  "requestId": "ticket-operation-memo-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare a hold for two exact items:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "parkMany",
    "sheetItemIds": [
      "sheet-example",
      "sheet-example-2"
    ],
    "parking": {
      "type": "DEACTIVATED",
      "memo": "Maintenance"
    },
    "confirmation": "CHANGE_TICKET_AVAILABILITY"
  },
  "requestId": "ticket-operation-park-many-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare release for two items sharing one existing tier:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "unparkMany",
    "sheetItemIds": [
      "sheet-example",
      "sheet-example-2"
    ],
    "confirmation": "CHANGE_TICKET_AVAILABILITY"
  },
  "requestId": "ticket-operation-unpark-many-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare a shared type/memo replacement on two parked items:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "parkingMetaMany",
    "sheetItemIds": [
      "sheet-example",
      "sheet-example-2"
    ],
    "parking": {
      "type": "EXTERNAL",
      "memo": "External allocation"
    }
  },
  "requestId": "ticket-operation-memo-many-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

Prepare deletion of the exact unoccupied schedule:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "deleteSchedule",
    "confirmation": "DELETE_SCHEDULE"
  },
  "requestId": "ticket-operation-delete-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```

## Dispatch and readback

All effects use BOOK_AND_TICKET_V3 on the selected API origin and exact installation consumer. There is no shop-store lookup. The host accepts only these bounded forms, without query/header extensions or caller transport bodies:

| Operation | Source request |
| --- | --- |
| park / parkMany | POST /seller/api/v3/schedules/{scheduleId}/ticketing-mng-sheet-items/dispatch with PARK, changed targetIds and complete parkingMeta. |
| parkingMeta / parkingMetaMany | Same route with UPDATE_PARKING_META, changed targetIds and complete parkingMeta. |
| unpark / unparkMany | Same route with CONVERT_TO_SLOT, changed targetIds and the observed common tierLabelId. |
| deleteSchedule | POST /seller/api/v3/schedules/dispatch with DELETE and exactly one scheduleId. |

Satisfied selected rows are excluded from targetIds. All selected rows must be eligible before dispatch; one invalid selection prevents the whole plan. An all-satisfied request is a verified no-op. Parking clears the affected slot fields and changes the relevant parked/online/available counts; metadata-only edits leave counts unchanged. Release changes availability/counts but must retain the observed tier and every policy price. It does not reprice or restore an old slot identity.

Release readback requires a present slotId for each changed item, unique across returned non-null slots, with matching seat, tier and policy projection and no price override. This workflow observes known sheet items and does not use the separate durable created-price receipt required by tierLink. No identity is adopted from matching titles or list differences. Slot history is not restored or cleared.

Full stable readback must preserve other sheet items, existing prices, schedule metadata and unaffected counts, including fingerprints of otherwise omitted buyer/assignment data. A buyer race, partial bulk effect, wrong slot, duplicate slot, count discrepancy or collateral change remains pending after a sent request. No second dispatch is sent for the remaining rows. Matching observations do not prove transaction atomicity or causality; histories and omitted projections are outside configuration verification.

Deletion requires an explicit same-identity DELETED schedule detail with preserved schedule metadata/counts, ignoring its generated deletion timestamp. Its result contains no active items. Counts are retained from the observed schedule; completion does not require resetting them to zero. A missing/forbidden/unavailable detail, 404, wrong identity or unrelated metadata change stays pending. This is schedule deletion, not deletion of a discount policy. No automatic recreation or deletion undo exists.

## Results and recovery

| Result | Meaning |
| --- | --- |
| COMMERCE_OPERATION_PLAN | dryRun:true, writesPerformed:false and the proposed request; request:null / noop:true means no effect. A new dry run creates no task; an existing task's dry run can be historical. |
| COMMERCE_OPERATION_COMPLETE | phase:done after matching readback or a verified no-op. Fresh confirmation is true; atomicSnapshot and causalityVerified remain false. |
| COMMERCE_OPERATION_PENDING | A sent operation is unresolved. Retain phase, lastCode, saveAcknowledged and journalPersistence; this is not an automatic background retry. |
| COMMERCE_JOURNAL_PERSISTENCE_FAILED | Journal durability is uncertain. Preserve the original request/outcome and do not invent a replacement task. |

The existing task type is commerce-ticket-operation; its journal phases are prepared, sent and done. writesPerformed describes the task: false for prepared/no-op, true after acknowledgement and null for an unacknowledged sent effect. It does not describe a new status/resume write. The sent phase is stored before the one dispatch.

Use [task_status](publ_task_status.md#e00003-ticket-operation-status) for historical stored progress and [task_resume](publ_task_resume.md#e00003-ticket-operation-recovery) for observation. Shared-host resume never sends a prepared or sent write. Prepared work requires identical original apply after current checks. Once sent, neither resume nor identical apply dispatches again. Matching exact-target readback can resolve a lost acknowledgement because these operations observe known identities; it does not prove causality.

Completed apply replay, status and completed resume are historical, with current verification false and no current verified destination. Read and prepare current state separately when needed. REQUEST_ID_CONFLICT rejects input differing from the saved request; COMMERCE_CONFLICT before dispatch requires resolving changed state. Do not replace an uncertain requestId, revision, selection or connection/installation binding.

A separate authorized reverse availability or memo change needs fresh observations and exact preparation after uncertainty is resolved. Unparking is not full restoration: it does not restore previous slot IDs or erase history. Deleted schedules have no automatic restoration. Actual restoration remains unverified.

## Console destination

Use the single labeled returned URL and exact authorized channel; do not construct a different host/path. Screen ID is channel.ticket-operations.

| Current operation | Path below /channels/{channelCode}/p-apps/E00003/ | Destination |
| --- | --- | --- |
| price or single/bulk park, unpark or parkingMeta | schedules/{scheduleId}/ticket-control-room | Exact selected schedule control room. |
| deleteSchedule | schedules | Surviving parent schedule list, including deletion preparation and no-op. Current list filters may differ. |

The host preserves only its validated operation-derived view, checks current schedule identity, counts/items and prepared targets, and rejects foreign or mismatched destinations. Fresh reads/plans/no-ops and verified completions retain the operation's location. Pending, error and historical results have no current verified link. A parent list does not recreate a deleted schedule, and a dry-run link does not prove a save.

## Change one seated-ticket price

Prepare the exact [price operation](ticket_operations_get.md#seated-ticket-price-preparation) and copy its revision. This is the eighth option of the existing operation method; it retains taskType commerce-ticket-operation and the exact schedule control-room destination. No new method, task type or price editor page is added.

One UPDATE_OVERRIDDEN_PRICES POST uses the same sheet dispatch route. It carries changed targetIds and the complete override array, preserving every unselected entry. The selected entry receives the channel currency, requested amount and source policy's public name. The caller supplies none of that raw array. ONLINE overrides are stored on the existing slot; PARKING overrides are stored on metadata. Stable readback verifies the exact keys, amount/currency, any returned public name and all preserved fields, including occupancy, counts, availability, slot identity and original schedule prices.

An equal effective amount is a no-op. Partial saves, altered other overrides, wrong projections or changed buyers remain pending without another dispatch. Status/resume use the same canonical commerce-ticket-operation journal and observation-only sent recovery already described above. Restoring a previous amount requires a separately authorized fresh preparation; setting a price back to a base amount does not remove an explicit override. The original price buttons expose only seated items, and no explicit per-item override reset/removal entry was found. This is not a backend-wide standing-price prohibition or a promise of a pending reset feature. Tier changes remain outside this option. Separate schedule-policy OVERRIDE/CHANGE and override-bearing parking release retain the unresolved boundaries in [source action scope](ticket_operations_get.md#source-action-boundaries).

Complete dry-run example; replace the revision with that returned for the exact price preparation:

```json
{
  "channelCode": "L2NoYW5uZWxzLzk4",
  "pAppCode": "E00003",
  "eventId": "event-example",
  "hallId": "hall-example",
  "scheduleId": "schedule-example",
  "operation": {
    "kind": "price",
    "sheetItemIds": [
      "sheet-example",
      "sheet-example-2"
    ],
    "eventPolicyTierPriceId": "policy-price-example",
    "payment": {
      "kind": "paid",
      "amount": "1500"
    }
  },
  "requestId": "ticket-seated-price-001",
  "expectedRevision": "0000000000000000000000000000000000000000000000000000000000000000",
  "dryRun": true
}
```