> ## 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.

# Create Experience

> Create a new experience (recurring offering) in your organization

# Create Experience

Creates a new experience (recurring offering — yoga class, workshop,
coaching slot, …) in your organization.

<Warning>
  **An experience without a recurrence has no bookable time slots.** The
  experience template (name, price, duration, location, …) is only half
  of what an attendee sees. The other half is a **recurrence** — the
  cadence (frequency, interval, days of week) plus session templates
  (start time, capacity, provider) that produces the actual bookable
  date/time grid.

  This endpoint helps you in two ways so you never ship an unbookable
  experience:

  1. **Auto-default**: if you supply at least one `providers[]` entry
     and omit `default_recurrence`, the API auto-attaches a starter
     recurrence (Mon–Fri 9am, UTC, never-ending, capacity =
     `default_capacity`). You can edit or replace it later via
     `POST /v1/experiences/{id}/recurrences`.
  2. **Explicit `default_recurrence` field**: pass the full recurrence
     body inline and we create both atomically.

  If you omit `default_recurrence` **and** pass no providers, the
  response will include `recurrence_required: true` plus a hint string —
  the experience exists but won't show slots until you call
  [Create Recurrence](/api-reference/recurrences/create-recurrence)
  yourself.
</Warning>

Requires the `experiences:write` scope.

## Idempotency

Pass an `Idempotency-Key` header (max 255 chars) to make POST retries safe. The first request executes the create; subsequent requests with the same key within 24 hours replay the original response verbatim — including the original status code — and add an `Idempotent-Replay: true` response header. Keys are scoped per API key, so two integrations can use the same key value without collision.

Two concurrent requests with the same key return `409 idempotent_request_in_progress` to the second caller.

## Request Body

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

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

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

<ParamField body="location" type="object" required>
  <Expandable>
    <ParamField body="type" type="string" required>`in_person`, `virtual`, or `hybrid`</ParamField>
    <ParamField body="venue" type="string">Venue name</ParamField>
    <ParamField body="address" type="string">Street address</ParamField>

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

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

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

    <ParamField body="instructions" type="string">Free-text instructions shown to attendees after they book.</ParamField>
    <ParamField body="video_link" type="string">Required when `type` is `virtual`/`hybrid`.</ParamField>
  </Expandable>
</ParamField>

<ParamField body="pricing" type="object" required>
  <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 (`USD`, `EUR`, …). Stored lower-cased.</ParamField>
    <ParamField body="amount" type="number" required>Price per session (use `0` for free).</ParamField>
  </Expandable>
</ParamField>

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

<ParamField body="scheduling_rules" type="object">
  Defaults: `booking_window: { min_hours_before: 1, max_days_ahead: 60 }` and `cancellation_policy: { refundable_until_hours_before: 24 }`.

  <Expandable>
    <ParamField body="booking_window" type="object">
      <Expandable>
        <ParamField body="min_hours_before" type="integer">Cut-off in hours before session start.</ParamField>
        <ParamField body="max_days_ahead" type="integer">Maximum days in advance bookings are accepted.</ParamField>
      </Expandable>
    </ParamField>

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

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

<ParamField body="providers" type="string[]">
  List of SpaceMember IDs running this experience. **Strongly
  recommended** — supplying at least one provider triggers the
  auto-default recurrence behavior described in the warning above. The
  first ID in the array is used as the provider for the auto-default.
</ParamField>

<ParamField body="default_recurrence" type="object">
  Optional. When supplied, a recurrence is created in the same request
  and the auto-default is skipped. Same shape as the body of
  [Create Recurrence](/api-reference/recurrences/create-recurrence):
  `provider_id`, `timezone`, `start_date`, `cadence`, `end_condition`,
  `session_templates`, and optional `status`. See that endpoint for
  field-level docs and validation rules.
</ParamField>

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

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

<ParamField body="space_identifier" type="string">
  Space the experience belongs to. Defaults to `GENERAL` (the organization-wide bucket).
</ParamField>

## Response

Returns the created experience with `201 Created`. When no recurrence
could be attached (omitted `default_recurrence` and empty `providers`),
the response also carries `recurrence_required: true` plus a `hint`
string telling you how to fix it.

<ResponseField name="data" type="object">
  Same schema as [Get Experience](/api-reference/experiences/get-experience).
</ResponseField>

<ResponseField name="recurrence_required" type="boolean">
  Present and `true` only when the experience was created without a
  recurrence. Omitted from the response otherwise. Until you attach a
  recurrence, the experience will not show bookable slots.
</ResponseField>

<ResponseField name="hint" type="string">
  Present alongside `recurrence_required: true`. Plain-English
  instructions on how to make the experience bookable.
</ResponseField>

<RequestExample>
  ```bash With explicit recurrence (recommended) theme={null}
  curl -X POST \
    -H "X-API-KEY: your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Sunset Yoga",
      "duration_minutes": 60,
      "default_capacity": 20,
      "location": { "type": "in_person", "city": "San Francisco" },
      "pricing": { "currency": "USD", "amount": 25 },
      "providers": ["sm_alice123"],
      "default_recurrence": {
        "provider_id": "sm_alice123",
        "timezone": "America/Los_Angeles",
        "start_date": "2026-08-01",
        "cadence": { "frequency": "weekly", "interval": 1, "days_of_week": [2, 4] },
        "end_condition": { "type": "never" },
        "session_templates": [
          { "start_time_of_day": "18:00", "capacity": 20, "provider_id": "sm_alice123" }
        ]
      }
    }' \
    "https://www.gomry.com/api/v1/experiences"
  ```

  ```bash With auto-default (Mon–Fri 9am UTC) theme={null}
  curl -X POST \
    -H "X-API-KEY: your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Sunset Yoga",
      "duration_minutes": 60,
      "default_capacity": 20,
      "location": { "type": "in_person", "city": "San Francisco" },
      "pricing": { "currency": "USD", "amount": 25 },
      "providers": ["sm_alice123"]
    }' \
    "https://www.gomry.com/api/v1/experiences"
  ```

  ```bash Without providers (no recurrence attached) theme={null}
  curl -X POST \
    -H "X-API-KEY: your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Sunset Yoga",
      "duration_minutes": 60,
      "default_capacity": 20,
      "location": { "type": "in_person", "city": "San Francisco" },
      "pricing": { "currency": "USD", "amount": 25 }
    }' \
    "https://www.gomry.com/api/v1/experiences"
  ```
</RequestExample>

<ResponseExample>
  ```json 201 (recurrence attached) theme={null}
  {
    "data": {
      "id": "AbCdEfGhIjKlMnOpQrSt",
      "name": "Sunset Yoga",
      "status": "active",
      "registration_status": "open",
      "duration_minutes": 60,
      "default_capacity": 20,
      "pricing": { "model": "per_session", "currency": "usd", "amount": 25 },
      "scheduling_rules": {
        "booking_window": { "min_hours_before": 1, "max_days_ahead": 60 },
        "cancellation_policy": { "refundable_until_hours_before": 24 }
      },
      "created_at": "2025-07-15T10:00:00.000Z",
      "updated_at": "2025-07-15T10:00:00.000Z"
    }
  }
  ```

  ```json 201 (no recurrence — needs follow-up call) theme={null}
  {
    "data": {
      "id": "AbCdEfGhIjKlMnOpQrSt",
      "name": "Sunset Yoga",
      "status": "active",
      "...": "..."
    },
    "recurrence_required": true,
    "hint": "No recurrence was attached. The experience will not show bookable slots until you call POST /v1/experiences/{id}/recurrences. Tip: include `providers: [\"<space_member_id>\"]` to auto-generate a Mon–Fri 9am starter recurrence on create."
  }
  ```

  ```json 400 theme={null}
  {
    "error": "Validation failed",
    "details": { "fieldErrors": { "duration_minutes": ["Required"] } }
  }
  ```

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