← Files WixARCHIVED FILE

skills/wix-headless-templates/events/seed/SEED.md

7.66 KB · Oct 9, 2026 · 12:02 UTC

↓ Download file

# Events — seeding

Seed by **running `seed-events.mjs` with a plan file** — don't hand-write the REST calls.
The script mints its own site token via the Wix CLI (logged-in session + `wix.config.json`
required), installs the Wix Events app if needed, sets the site currency when the plan names one, and creates
everything in the one order that works (create DRAFT → tiers → publish — the registration
type is immutable and publishing is one-way).

```bash
# from the project root (where wix.config.json lives):
node <SKILL_ROOT>/templates/events/seed/seed-events.mjs plan.json
```

`plan.json` is plain data — write it from the brief. **Default to 3 events** (the seed shows
the shape; the owner adds the rest in the dashboard) and make them exercise the UI: mix
`TICKETING` and `RSVP` (≥1 of each), give a ticketed event 2 tiers, and give every event an
image (an events page without images looks broken) — the default is an `imagePrompt`
(AI-generated, ~1 Wix AI credit per image, account-billed): brand-contextual — subject,
aesthetic/mood, palette, lighting — always ending "no text, no watermarks". At least one image in the set shows the real subject of the business — the actual product/space/service, not abstract decoration. For an asset the user actually
supplied use `imagePath` (a file on this machine — uploaded to Wix Media) or `imageUrl`
(their own hosted URL; verify it with `curl -sI` → 200) — never a stock-photo or guessed URL. Images resolve in parallel and never block the
seed; a failed image leaves that event text-only.

```json
{
  "events": [
    { "type": "TICKETING", "title": "Summer Synth Festival",
      "shortDescription": "One night of analog sound under the stars.",
      "startDate": "2026-11-07T03:30:00.000Z", "endDate": "2026-11-07T07:00:00.000Z",
      "timeZoneId": "America/Los_Angeles",
      "location": { "name": "The Echo Lot", "type": "VENUE",
        "address": { "addressLine": "120 Harbor St", "city": "Seattle", "subdivision": "US-WA", "postalCode": "98101", "country": "US" } },
      "ticketTiers": [
        { "name": "General Admission", "price": "45.00", "initialLimit": 200 },
        { "name": "Front Row", "price": "85.00", "description": "First two rows.", "initialLimit": 40 }
      ],
      "category": "Concerts", "imageUrl": "https://…" },
    { "type": "TICKETING", "title": "Vinyl Mixing Workshop",
      "shortDescription": "Hands-on turntable session, decks provided.",
      "startDate": "2026-11-14T18:00:00.000Z", "endDate": "2026-11-14T20:00:00.000Z",
      "timeZoneId": "America/Los_Angeles",
      "location": { "name": "Studio B", "type": "VENUE",
        "address": { "addressLine": "9 Pine Ave", "city": "Seattle", "subdivision": "US-WA", "postalCode": "98101", "country": "US" } },
      "ticketTiers": [{ "name": "Workshop Seat", "price": "30.00", "initialLimit": 16 }],
      "category": "Workshops", "imageUrl": "https://…" },
    { "type": "RSVP", "title": "Community Listening Night",
      "shortDescription": "Free open-deck evening — bring a record.",
      "startDate": "2026-11-20T19:00:00.000Z", "endDate": "2026-11-20T22:00:00.000Z",
      "timeZoneId": "America/Los_Angeles",
      "location": { "name": "The Back Room", "type": "VENUE",
        "address": { "addressLine": "120 Harbor St", "city": "Seattle", "subdivision": "US-WA", "postalCode": "98101", "country": "US" } },
      "category": "Community", "imageUrl": "https://…" }
  ]
}
```

- `type` — `TICKETING` (paid tiers; buyers pay on Wix's hosted checkout) or `RSVP` (free;
  Wix creates the name+email form — the seed adds no fields; the owner extends it in the
  dashboard and the site renders whatever the form holds). **Immutable after create** —
  decide from the brief, never plan to convert.
- **Dates are future ISO-8601 UTC** (`…Z`), `endDate` after `startDate`, `timeZoneId` an
  IANA tz. A past event isn't registerable and won't show in the live listing; no date in
  the brief → default ~60–90 days out and say so.
- `ticketTiers` — TICKETING only, created before publish. `price` is a **decimal STRING**
  (`"45.00"`, never a number), `name` ≤ 30 chars, omit `initialLimit` for unlimited. Tier
  currency is the site currency, fixed at creation: a wrong one means deleting the event.
  `feeType` (optional) says who pays the Wix ticket service fee: `FEE_INCLUDED` (default — out of
  the price), `FEE_ADDED_AT_CHECKOUT` (the buyer pays 2.5% on top; the event page shows the line),
  or `NO_FEE` (free tickets; sites that don't require a fee). When Wix answers `INVALID_FEE_TYPE`
  the seed retries the same tier with `NO_FEE`, then `FEE_ADDED_AT_CHECKOUT`, and reports the one
  that took in the result's per-event `feeTypes`.
- `currency` — 3-letter ISO code at the top of the plan, set **only when the brief names one**: a
  sentence about currency, or a price written with its unit ("9 dollars", "$9", "€20"). Do **not**
  infer it from a language, a country, or an address. The seed sets the site to it before creating
  anything, because prices are stored in the site currency at create time; a new site starts in the
  currency of the account that created it, not the business's.
- `location` — `{ name, type: "VENUE", address }` (address `subdivision` is ISO-3166-2 like
  `US-WA`, `country` ISO alpha-2), `{ name, type: "ONLINE" }`, or
  `{ locationTbd: true, name }`.
- `category` — a name; created and assigned for you. Skip when the brief has no grouping.
- `rsvpResponseType` — `"YES_AND_NO"` to let guests decline (default `"YES_ONLY"`).
- `rsvpLimit` — RSVP only: the number of spots; `waitlist: true` opens a wait list once they are
  taken (the page then offers "Join the waitlist").
- `registrationOpensAt` — RSVP only: a future ISO-8601 UTC instant. The event publishes with
  registration SCHEDULED and the page says when it opens — for a brief like "RSVP opens next week".
  The API pairs it with a closing instant: `registrationClosesAt` (default: the event's `startDate`).
- `guests` — RSVP only: how many additional guests one RSVP may bring. Added to the registration
  form through the Events Forms API after the event is created (a count 0..N and the guests' names);
  the result's per-event `guestControl` is `true` when it landed. When it did not, the event exists
  without it and the owner adds the guest control in the dashboard — say so in the closing message.

The result JSON carries a `notes` array — when any event is ticketed it reminds that
**completing a paid purchase needs a premium plan + a configured payment method** in the
dashboard. That's an owner step, not a seeding failure; relay it.

**Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
seems needed.

## Supplied content

The general rules are in `templates/shared/SUPPLIED-CONTENT.md`. For events, each event the user
lists is one entry. Its title becomes `title`; its date and time become `startDate` and `endDate` in
ISO with the `timeZoneId` the user stated; the venue and address become `location`; named tickets
with prices become `ticketTiers` on a `TICKETING` event, and an event with no tickets is `RSVP`; a
category becomes `category`; their image becomes `imageUrl`. A date without a year or without a
time zone is a question for the user, never a guess.

## Escape hatch — individual functions
`setupEvents` composes exported steps — `installEventsApp`, `getSiteCurrency`, `createEvent`,
`createTicketTiers`, `publishEvent`, `createEventCategories`, `assignEventsToCategory`,
`importImage`, `setEventMainImage`, plus `makeCtx()` — import them only for a partial re-seed.

## Reference
Unexpected shape or an uncovered operation → read the live Wix API reference; every call the script
makes carries a `docs:` line with its reference page.

SHA-256: 504f995fecbbc9a2a5a787435b9a9edc1aaa985305768f28e48c369d78bc5ecb