> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Attend an Event

## Article: Attend an Event

## Article Link: https://dev.wix.com/docs/api-reference/business-solutions/events/skills/attend-an-event.md

## Article Content:

# RECIPE: Attend an Event

## When to use this recipe

- "What's happening next month?" / "Which events are free?" / "Show me only the Community events"
- "Tell me about the retreat: when, where, how much?"
- "I'd like to come to Open Studio Night, I'm Dana Cohen…" (RSVP yes) / "I can't make it after all" (RSVP no)
- "Get me 2 Early Bird tickets" / "Are there tickets left?"
- "Add it to my calendar"

## Inputs you need

| Input | How to get it |
|---|---|
| Visitor token | STEP 1 |
| Event `id`, `slug`, `registration.initialType` (`RSVP` or `TICKETING`), dates, location, categories, calendar links | STEP 2 |
| Ticket definition `id`s and prices (ticketed events) | STEP 3 |
| Guest first name, last name, email (RSVP) — the form is built in, do not invent extra fields | Ask the visitor |
| `reservationId` (tickets) | STEP 5 |

## Decision tree

- **"What's on?" / "Which are free?"** → STEP 1 + STEP 2. Free = `registration.initialType === "RSVP"`.
- **"Only the <category> events"** → STEP 2 with `fields: ["CATEGORIES"]`, filter client-side on `categories.categories[].name`.
- **"Tell me about X / how much are tickets?"** → STEP 2 + STEP 3 (ticketed only).
- **"I'll come" / "I can't come" (free event)** → STEP 2 → STEP 4. `status: "YES"`; `"NO"` only when `registration.rsvp.responseType === "YES_AND_NO"`.
- **"Get me N tickets"** → STEP 2 → STEP 3 → STEP 5 → STEP 6. Expect the payment gate on sites without a payment provider (Common errors #4).
- **"Add to calendar"** → STEP 2: `calendarUrls.google` / `calendarUrls.ics`.

---

## Date and time rules

- `dateAndTimeSettings.formatted.dateAndTime` is already a human string in the event's timezone (e.g. `October 24, 2026, 9:00 AM – 1:30 PM GMT+3`) — quote it as is.
- `dateAndTimeSettings.startDate` is UTC; use it only for sorting and for "next month" arithmetic in the business timezone (`GetBusinessDetails` → `timeZone`).
- Never list past events: filter `status` to `UPCOMING`/`STARTED`.

---

## STEP 1: Get a visitor token

`GenerateVisitorToken` once; reuse it.

---

## STEP 2: List or find events

`POST https://www.wixapis.com/events/v3/events/query`

```bash
curl -X POST 'https://www.wixapis.com/events/v3/events/query' \
-H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' \
-d '{
  "query": {
    "filter": { "status": { "$in": ["UPCOMING", "STARTED"] } },
    "sort": [{ "fieldName": "dateAndTimeSettings.startDate", "order": "ASC" }],
    "paging": { "limit": 100 }
  },
  "fields": ["DETAILS", "TEXTS", "REGISTRATION", "URLS", "CATEGORIES"]
}'
```

Filtering by `slug` in the query returned nothing on this site — fetch the upcoming list and match `slug`/`title` client-side.

```jsonc
{ "events": [{
  "id": "2fd1a358-…",                                        // ← eventId for STEP 3, 4
  "slug": "half-day-clarity-retreat",                        // ← eventSlug for the checkout redirect
  "title": "Half-Day Clarity Retreat",
  "shortDescription": "…",
  "status": "UPCOMING",
  "dateAndTimeSettings": { "startDate": "2026-10-24T06:00:00Z", "timeZoneId": "Asia/Jerusalem",
                           "formatted": { "dateAndTime": "October 24, 2026, 9:00 AM – 1:30 PM GMT+3" } },
  "location": { "name": "Clearspace Studio", "type": "VENUE", "address": { "formatted": "…" } },
  "registration": { "initialType": "TICKETING", "status": "OPEN_TICKETS",   // RSVP → "OPEN_RSVP"
                    "rsvp": { "responseType": "YES_ONLY" } },
  "categories": { "categories": [{ "id": "…", "name": "Retreats" }] },     // only with CATEGORIES
  "calendarUrls": { "google": "https://…", "ics": "https://…" }             // only with URLS
}] }
```

---

## STEP 3: Ticket types and prices (ticketed events)

`POST https://www.wixapis.com/events/v1/checkout/available-tickets/query` — the **visitor-public** read. `ticket-definitions` endpoints are management-only and 403 the visitor.

```bash
curl -X POST 'https://www.wixapis.com/events/v1/checkout/available-tickets/query' \
-H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' \
-d '{ "filter": { "eventId": "<EVENT_GUID>" }, "limit": 20 }'
```

```jsonc
{ "definitions": [{
  "id": "b1ac0577-…",                              // ← ticketDefinitionId for STEP 5
  "name": "Early Bird", "description": "Book before October 10.",
  "price": { "amount": "290.00", "currency": "ILS", "value": "290.00" },
  "free": false,
  "limitPerCheckout": 6,                           // max per order
  "saleStatus": "SALE_STARTED"                     // SALE_STARTED | SALE_SCHEDULED | SALE_ENDED
}] }
```

Remaining stock is **not** exposed to visitors — answer "on sale" / "sale ended", never a count. Empty `definitions` with `saleStatus` missing means sold out or not yet on sale.

---

## STEP 4: RSVP to a free event

`POST https://www.wixapis.com/events/v2/rsvps` — body **must be wrapped in `rsvp`**.

```bash
curl -X POST 'https://www.wixapis.com/events/v2/rsvps' \
-H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' \
-d '{ "rsvp": { "eventId": "<EVENT_GUID>", "firstName": "Dana", "lastName": "Cohen", "email": "dana@example.com", "status": "YES" } }'
```

→ `{ "rsvp": { "id": "…", "status": "YES", "email": "dana@example.com", … } }`. Tell the visitor a confirmation email is on its way. Use `"status": "NO"` only when the event's `rsvp.responseType` is `YES_AND_NO`.

---

## STEP 5: Reserve paid tickets

`POST https://www.wixapis.com/events/v1/ticket-reservations` — body **must be wrapped in `ticketReservation`**.

```bash
curl -X POST 'https://www.wixapis.com/events/v1/ticket-reservations' \
-H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' \
-d '{ "ticketReservation": { "tickets": [{ "ticketDefinitionId": "<TICKET_DEF_GUID>", "quantity": 2 }] } }'
```

Success → `{ "id": "<reservationId>", "status": "PENDING", "expires": "…" }` (held ~20 minutes). On a site with no payment provider the same call returns **`403 { "message": "No payment method configured" }`** — that is a site-owner setting, not a bug; tell the visitor tickets aren't on sale online yet and offer the contact details from `GetBusinessDetails`.

---

## STEP 6: Send the visitor to the ticket checkout

`POST https://www.wixapis.com/_api/redirects-api/v1/redirect-session`

```json
{ "eventsCheckout": { "reservationId": "<RESERVATION_ID>", "eventSlug": "<EVENT_SLUG>" },
  "callbacks": { "thankYouPageUrl": "https://<site>/event-confirmation", "postFlowUrl": "https://<site>/events/<EVENT_SLUG>" } }
```

→ `redirectSession.fullUrl`. Never hand-build `/event-details/<slug>/ticket-form` (404 on headless sites) and never call the legacy `POST /events/v1/checkout` to pay inline.

---

## Common errors and how to avoid them

### 1. `ExecuteWixAPI` masks the real error as "Visitor token rejected (HTTP 403)"

Both the `400 ticketReservation must not be empty` and the `403 No payment method configured` came back as a token error from the sandbox. Re-run the single call with `CallWixSiteAPI` to read the real message before deciding what to tell the visitor.

### 2. `400 rsvp.firstName must not be empty` / `ticketReservation must not be empty`

You sent a flat body. Wrap: `{ "rsvp": { … } }` and `{ "ticketReservation": { "tickets": [ … ] } }`.

### 3. `POST /events/v1/tickets/available/query` → 404

The visitor read is `POST /events/v1/checkout/available-tickets/query`. Docs search "available tickets" lists it as *Query Available Tickets*.

### 4. `403 No payment method configured` on ticket reservation

Expected on sites without a payment provider / premium plan. Do not retry with another token; explain and point to the business contact.

### 5. Query by `slug` returns `events: []`

Query the upcoming list and match client-side.

### 6. Listing categories through `/events/v1/categories`

Management-only. Request `fields: ["CATEGORIES"]` on the event query and read `categories.categories[].name`.

---

## Constants

| Constant | Value |
|---|---|
| Wix Events app id | `140603ad-af8d-84a5-2c80-a0f60cb47351` |
| Events query fields | `["DETAILS", "TEXTS", "REGISTRATION", "URLS", "CATEGORIES"]` |

---

## References

- [Query Events (V3)](https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/query-events.md)
- [Query Available Tickets](https://dev.wix.com/docs/api-reference/business-solutions/events/attendance-and-checkout/orders/query-available-tickets.md)
- [Create RSVP (V2)](https://dev.wix.com/docs/api-reference/business-solutions/events/attendance-and-checkout/rsvp-v2/create-rsvp.md)
- [Create Ticket Reservation](https://dev.wix.com/docs/api-reference/business-solutions/events/attendance-and-checkout/ticket-reservations/create-ticket-reservation.md)
- [Create Redirect Session](https://dev.wix.com/docs/api-reference/business-management/redirects/redirect-session/create-redirect-session.md)