ticket_discount_creation_apply
# ticket_discount_creation_apply
Creates a discount policy for an event or copies an existing one, as the console discount screen does. Called without confirmToken it previews and returns a confirmToken; repeating the same input with it executes once.
## Inputs
| Field | Required here | Contract |
| --- | --- | --- |
| `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. |
| `operation` | Yes | one of: `create`, `copy` (by `kind`) |
| `operation.title` | Yes | When `operation.kind` is `create`: string |
| `operation.presentationalTitle` | Yes | When `operation.kind` is `create`: string |
| `operation.labelIds` | Yes | When `operation.kind` is `create`: 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.; max items 10 |
| `operation.translation` | No | When `operation.kind` is `create`: object |
| `operation.translation.presentationalTitle` | Yes | When `operation.kind` is `create`: object |
| `operation.translation.presentationalTitle.ko` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.en` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.ja` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.zh` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.zh-Hant` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.fr` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.es` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.vi` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.ru` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.translation.presentationalTitle.it` | No | When `operation.kind` is `create`: string; max length 20000 |
| `operation.sourcePolicyId` | Yes | When `operation.kind` is `copy`: 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 `copy`: `COPY_DISCOUNT_POLICY` |
| `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. |
## Usage
The operations are described in [ticket_discount_creation_get](ticket_discount_creation_get.md).
```json
{"eventId": "event-example", "operation": {"kind": "copy", "sourcePolicyId": "discount-example", "confirmation": "COPY_DISCOUNT_POLICY"}}
```
A new discount is based on the event's default policy, as in the console. A copy keeps the source's sales conditions, prices and labels; the names the service generates for the copy are reported. Translations, given or copied, are read back with the new policy.
The new discount's identity is taken from the service's answer and read back twice. If the answer carried no identity, the task stays pending; the discount is never matched by name or by a list difference, and it is never created again. While a creation or copy for an event is unfinished, another creation or copy for the same event is refused. Set prices and conditions afterwards with [ticket_discount_settings_apply](ticket_discount_settings_apply.md).
## Not offered here
Checkout, schedule changes, notifications, refunds and automatic deletion of a created discount.
## Preview and execution
Call the tool without `confirmToken` first. It reads the current state, checks the change and returns a preview: the request it would send (`request:null` when nothing would change), the current values, a `confirmToken`, `confirmTokenExpiresAt` and `writesPerformed:false`. Nothing is saved. Show the preview to the person; after they agree, call the tool again with exactly the same input and that `confirmToken`. The token works once, for this input only, within 10 minutes.
Nothing is sent when the input differs from the preview (`CONFIRM_TOKEN_INPUT_CHANGED`), the token expired (`CONFIRM_TOKEN_EXPIRED`) or belongs to another tool or channel (`CONFIRM_TOKEN_INVALID`), or the current state changed after the preview (`COMMERCE_CONFLICT` or `COMMERCE_CHANGED`). Call the tool again with the intended input to get a new preview.
## Results and recovery
`COMMERCE_OPERATION_COMPLETE` means two fresh reads matched the requested change and the other returned values stayed as they were; `noop:true` means nothing needed to change and nothing was sent. `COMMERCE_OPERATION_PENDING` means the change was sent but could not be confirmed (see `lastCode`); `COMMERCE_JOURNAL_PERSISTENCE_FAILED` means the saved progress itself is uncertain. `writesPerformed` is false when nothing was sent, true after the service acknowledged the change and null when a sent change was not acknowledged.
The result carries a `taskId` (task type `commerce-ticket-discount-creation`). Observe it with [task_status](publ_task_status.md) or [task_resume](publ_task_resume.md); both only read. An uncertain execution is never sent again: resolve it before previewing the same change again. Repeating the same input with the same `confirmToken` returns to that task and never resends what was already sent. A completed result returned again later is the stored result, not the current state; read current values with [ticket_discount_settings_get](ticket_discount_settings_get.md). There is no automatic rollback; undoing a change is a new change with its own preview.