> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gomry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Experience

> Partially update an experience in your organization

# Update Experience

Partially updates an experience. Only the fields supplied in the body
are written — omitted fields are left unchanged. The experience must
belong to the organization associated with the API key; cross-org
requests return `404 Not Found` with no information leak.

Requires the `experiences:write` scope.

## Path Parameters

<ParamField path="experience_id" type="string" required>
  Experience ID (the service catalog document ID).
</ParamField>

## Request Body

At least one field is required. Unknown fields are rejected with `400`.

<ParamField body="name" type="string">
  Experience name (1–120 chars).
</ParamField>

<ParamField body="description" type="string">
  Long-form description shown on the public booking page.
</ParamField>

<ParamField body="duration_minutes" type="integer">
  Length of one session in minutes (1..1440).
</ParamField>

<ParamField body="default_capacity" type="integer">
  Maximum attendees per session (1..10000).
</ParamField>

<ParamField body="location" type="object">
  Replace the location object. `type` is required when `location` is supplied.

  <Expandable>
    <ParamField body="type" type="enum" required>`in_person`, `virtual`, or `hybrid`</ParamField>

    <ParamField body="venue" type="string" />

    <ParamField body="address" type="string" />

    <ParamField body="city" type="string" />

    <ParamField body="state" type="string" />

    <ParamField body="country" type="string" />

    <ParamField body="instructions" type="string" />

    <ParamField body="video_link" type="string" />
  </Expandable>
</ParamField>

<ParamField body="pricing" type="object">
  Replace the pricing object. Currency is normalised to lowercase before
  persistence. When the currency changes, all child ticket classes have
  their pricing currency cascaded automatically — booking flows that
  validate parent/child currency equality continue to work.

  <Expandable>
    <ParamField body="model" type="string">Only `per_session` is supported via the public API today (defaults to `per_session`).</ParamField>
    <ParamField body="currency" type="string" required>ISO 4217 currency code.</ParamField>
    <ParamField body="amount" type="number" required>Price per session.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="scheduling_rules" type="object">
  Partial scheduling rules. Each nested object (`booking_window`,
  `cancellation_policy`) is replaced wholesale if supplied; omit a nested
  object to keep its existing values. Invariants (`min_hours_before >= 0`,
  `max_days_ahead > 0`, `refundable_until_hours_before >= 0`) are enforced
  on the merged result.

  <Expandable>
    <ParamField body="booking_window" type="object">
      <Expandable>
        <ParamField body="min_hours_before" type="integer" required />

        <ParamField body="max_days_ahead" type="integer" required />
      </Expandable>
    </ParamField>

    <ParamField body="cancellation_policy" type="object">
      <Expandable>
        <ParamField body="refundable_until_hours_before" type="integer" required />

        <ParamField body="late_cancel_fee" type="object">Optional `{ currency, amount }`.</ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="providers" type="string[]">
  Replace the providers list. Pass `[]` to remove all providers.
</ParamField>

<ParamField body="required_contact_method" type="enum">
  `none`, `email`, or `email_and_phone`.
</ParamField>

<ParamField body="max_booking_quantity" type="integer">
  Upper bound on seats per single booking (1..50).
</ParamField>

<ParamField body="status" type="enum">
  `active` or `inactive`. Inactive experiences are hidden from the public
  catalog and reject new bookings.
</ParamField>

<ParamField body="registration_status" type="enum">
  `open` or `closed`. When `closed` the experience stays publicly
  visible but the booking CTA is hidden.
</ParamField>

## Response

Returns the updated experience as serialized by
`GET /experiences/{experience_id}`.

<RequestExample>
  ```bash cURL theme={null}
  curl -X PATCH \
    -H "X-API-KEY: your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Sunset Yoga — Premium",
      "pricing": { "model": "per_session", "currency": "EUR", "amount": 35 },
      "scheduling_rules": { "booking_window": { "min_hours_before": 2, "max_days_ahead": 90 } }
    }' \
    "https://www.gomry.com/api/v1/experiences/AbCdEfGhIjKlMnOpQrSt"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "data": {
      "id": "AbCdEfGhIjKlMnOpQrSt",
      "name": "Sunset Yoga — Premium",
      "status": "active",
      "registration_status": "open",
      "duration_minutes": 60,
      "default_capacity": 20,
      "pricing": { "model": "per_session", "currency": "eur", "amount": 35 },
      "scheduling_rules": {
        "booking_window": { "min_hours_before": 2, "max_days_ahead": 90 },
        "cancellation_policy": { "refundable_until_hours_before": 24 }
      },
      "created_at": "2025-07-15T10:00:00.000Z",
      "updated_at": "2025-07-15T11:00:00.000Z"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "error": "At least one field is required"
  }
  ```

  ```json 400 theme={null}
  {
    "error": "defaultCapacity must be >= 1"
  }
  ```

  ```json 404 theme={null}
  {
    "error": "Experience not found"
  }
  ```

  ```json 403 theme={null}
  {
    "error": "insufficient_scope",
    "message": "This API key does not have 'write' access to 'experiences'.",
    "required_scope": "experiences:write"
  }
  ```
</ResponseExample>
