---
title: "Update Commission Rule"
method: PUT
path: "/api/v1/commission-rules/{rule_id}"
tags: ["commission-rules"]
---

# Update Commission Rule

`PUT /api/v1/commission-rules/{rule_id}`

Edit or close a rule. Closing = setting ``effective_to``.

There is no DELETE: a rule that priced any booking is undeletable at the
DB level (ON DELETE RESTRICT), and superseding a contract means closing
the old line and creating a new one under a new ``contract_version``.

## Path parameters

- `rule_id` string, uuid, required

## Request body

- CommissionRuleUpdate — A change to one rule; only the fields present in the body are applied. Closing a line ("this rate stopped applying on D") is a PUT that sets ``effective_to`` — there is no DELETE, because a rule that priced any booking cannot be deleted (``ON DELETE RESTRICT``) and superseding a contract means closing the old line and opening a new one.
  - `property_code` string, nullable
  - `channel` 'voice_agent' | 'text_agent' | 'hotel_agent' | 'ota' | 'website' | 'direct_pms' | 'unknown' — Where a canonical booking originated (normalized channel attribution). NULL on ``BookingRecord`` means "not yet derived" (legacy rows before the PR 3 backfill); UNKNOWN means "derived but undeterminable" — the two are deliberately distinct (Direct Bookings ontology §6).
  - `provider` string, nullable
  - `cost_type` 'ota_commission' | 'payment_fee' | 'channel_manager_fee' | 'marketing_fee' — The kinds of charge a ``CommissionRule`` can express (PR 17 §4). Distinct cost types STACK (one cost component each) while two rules of the same cost type compete on scope specificity. A free-form string therefore lets a user double-charge themselves by inventing "commission" alongside "ota_commission" — so the API constrains new writes to this vocabulary. The column stays a ``String(50)``: existing rows are not rewritten and no migration is needed. ``OTA_COMMISSION`` is the default for the one-line entry path (the hotelier typing "Booking.com 18%" never chooses a cost type).
  - `contract_basis` 'commissionable' | 'net_rate' | 'metasearch' | 'own_cost' — What kind of commercial arrangement a ``CommissionRule`` records (PR 19). A rate is not a contract. "18% of gross" and "we are paid a contracted net amount" are different economics, and applying the first shape to the second produces a confident €0.00 rather than a missing number — the most expensive channel in the portfolio rendered as free. - ``COMMISSIONABLE`` — the hotel sets the rate and the provider invoices a percentage (or a flat fee). The PR 12 behaviour, and the default so every pre-PR-19 row keeps exactly the meaning it had. - ``NET_RATE`` — the hotel is paid a contracted net amount; the provider's margin is not a cost the hotel pays. No commission is computed, and the reported value (when present) already IS the net. - ``METASEARCH`` — billed per click or per campaign, never per booking. The rule records the arrangement so the source does not read as free; CPC spend has no per-booking home and this PR does not invent one. - ``OWN_COST`` — the hotel's own per-booking costs on direct business (payment gateway, booking engine). Computes exactly like ``COMMISSIONABLE``; kept separate so "distribution cost" and "cost of taking a direct booking" never render as the same line. ``NET_RATE`` and ``METASEARCH`` carry NO charge (a CHECK enforces it): a percentage on a net-rate rule is a configuration error that would otherwise price silently.
  - `rate` union
    - number
    - string
  - `fixed_amount` union
    - number
    - string
  - `fixed_currency` string, nullable
  - `effective_from` string, date, nullable
  - `effective_to` string, date, nullable
  - `contract_version` string, nullable

## Response `200`

Successful Response

- CommissionRuleRead
  - `id` string, uuid, required
  - `property_code` string, nullable, required
  - `channel` 'voice_agent' | 'text_agent' | 'hotel_agent' | 'ota' | 'website' | 'direct_pms' | 'unknown', required — Where a canonical booking originated (normalized channel attribution). NULL on ``BookingRecord`` means "not yet derived" (legacy rows before the PR 3 backfill); UNKNOWN means "derived but undeterminable" — the two are deliberately distinct (Direct Bookings ontology §6).
  - `provider` string, nullable, required
  - `cost_type` string, required
  - `contract_basis` 'commissionable' | 'net_rate' | 'metasearch' | 'own_cost', required — What kind of commercial arrangement a ``CommissionRule`` records (PR 19). A rate is not a contract. "18% of gross" and "we are paid a contracted net amount" are different economics, and applying the first shape to the second produces a confident €0.00 rather than a missing number — the most expensive channel in the portfolio rendered as free. - ``COMMISSIONABLE`` — the hotel sets the rate and the provider invoices a percentage (or a flat fee). The PR 12 behaviour, and the default so every pre-PR-19 row keeps exactly the meaning it had. - ``NET_RATE`` — the hotel is paid a contracted net amount; the provider's margin is not a cost the hotel pays. No commission is computed, and the reported value (when present) already IS the net. - ``METASEARCH`` — billed per click or per campaign, never per booking. The rule records the arrangement so the source does not read as free; CPC spend has no per-booking home and this PR does not invent one. - ``OWN_COST`` — the hotel's own per-booking costs on direct business (payment gateway, booking engine). Computes exactly like ``COMMISSIONABLE``; kept separate so "distribution cost" and "cost of taking a direct booking" never render as the same line. ``NET_RATE`` and ``METASEARCH`` carry NO charge (a CHECK enforces it): a percentage on a net-rate rule is a configuration error that would otherwise price silently.
  - `rate` string, nullable, required
  - `fixed_amount` string, nullable, required
  - `fixed_currency` string, nullable, required
  - `effective_from` string, date, required
  - `effective_to` string, date, nullable, required
  - `contract_version` string, required
  - `tenant_id` string, uuid, required

## Other responses

- `404` — Resource not found
- `422` — Validation Error

---

[API](https://skmtc.dev/getanana/apis/cleon-api.md) · [All operations](https://skmtc.dev/getanana/apis/cleon-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/getanana/cleon-api/revisions/c0f54348e251/schema)
