orders = seatlayer.orders().listEventOrders("summer-gala");
+String csv = seatlayer.orders().exportEventOrdersCsv("summer-gala");
+seatlayer.orders().refundEventOrder(
+ "summer-gala", "ord_1042", Map.of("amountMinor", 500), "refund-ord_1042");
+
+seatlayer.holders().createHolderTransfer("holder-1042", Map.of(
+ "ticketIds", List.of("tkt_1"),
+ "toEmail", "friend@example.com"), null);
+```
+
+Request bodies are maps in the API's own field names. To send an explicit
+`null`, such as clearing a booking fee, use a map that allows null values
+(`LinkedHashMap`). The three CSV exports (`seasons().exportSeasonHoldersCsv`,
+`seasons().exportSeasonOrdersCsv`, `orders().exportEventOrdersCsv`) return the
+CSV text as a `String`. `seasons().deleteSeasonPlan` and
+`events().deleteEventDiscountCode` return nothing: the API answers 204.
+
## Test vs live
Keys carry their own mode. `sk_test_…` keys can only touch test-mode events and `sk_live_…` only
@@ -224,6 +324,8 @@ exactly when you don't want that, and you can control it explicitly:
seatlayer.events().list(EventListOptions.builder().limit(50).counts(false).build());
```
+Add `.seriesKey("ser_1")` to list only the dates of one event series.
+
## Keeping a hold alive
When an order takes longer than the checkout window (an invoice, a phone sale), extend rather than
@@ -315,17 +417,32 @@ support requests. All are unchecked, so they do not force `throws` clauses throu
## Reliability
**Retries and idempotency.** Reads (`GET`/`HEAD`) retry connection failures, 408, 429 and 5xx with
-exponential backoff and full jitter; `Retry-After` wins when the server sends it. Fourteen mutations
-use exact header replay: `charts().create`, `charts().copy`,
-`templates().instantiateTemplate`, `events().create`, `workspaces().create`,
-`performanceGroups().create`, `seasons().createSeason`, `seasons().updateSeason`,
-`seasons().deleteSeason`, `seasons().createSeasonPlan`, `seasons().duplicateSeasonToLive`,
-`seasons().createSeasonHolderImport`, `seasons().createSeasonRenewalOffers`, and
-`seasons().createSeasonAmendment`. They generate an `Idempotency-Key` when absent and reuse that key
-across every attempt. Overloads that accept a key let you provide a stable provisioning key instead.
+exponential backoff and full jitter; `Retry-After` wins when the server sends it. Forty-one
+mutations use exact header replay:
+
+- `charts().create`, `charts().copy`, `templates().instantiateTemplate`, `events().create`,
+ `workspaces().create`, and `performanceGroups().create`
+- 26 on `seasons()`: `createSeason`, `updateSeason`, `deleteSeason`, `createSeasonPlan`,
+ `updateSeasonPlan`, `deleteSeasonPlan`, `publishSeason`, `duplicateSeasonToLive`,
+ `createSeasonHolderImport`, `createSeasonHolderImportFromSeason`, `createSeasonRenewalOffers`,
+ `createSeasonAmendment`, `createSeasonPerformances`, `attachSeasonPerformances`,
+ `deleteSeasonPerformance`, `markSeasonPerformancePast`, `createSeasonCheckoutTest`,
+ `replaceSeasonPackagePrices`, `attachSeasonPlanPerformance`, `deleteSeasonPlanPerformance`,
+ `refundSeasonOrder`, `cancelSeasonOrder`, `cancelSeasonOrderDate`, `refundSeasonPerformance`,
+ `releaseSeasonLapsedOffers`, and `createSeasonRenewalCheckout`
+- `holders().updateHolder`, `holders().createHolderTransfer`, `holders().createHolderReturn`,
+ `holders().createHolderRenewalCheckout`, `orders().refundEventOrder`, and
+ `orders().cancelEventOrder`
+- `eventSeries().createEventSeries`, `eventSeries().addEventSeriesDates`, and
+ `eventSeries().updateEventSeries`
+
+They generate an `Idempotency-Key` when absent and reuse that key across every attempt. Overloads
+that accept a key let you provide a stable provisioning key instead; pass `null` to have one
+generated.
All remaining SDK mutations are single-attempt: holds, bookings, lifecycle changes, channel
-changes, show-once secret creation, and raw requests. Some have a server-side domain idempotency
+changes, show-once secret creation, ticket and renewal emails, renewal links, discount codes,
+event checkout, gateway, fee and sales changes, and raw requests. Some have a server-side domain idempotency
contract, but the SDK does not retry them automatically. Reconcile bookings with their required
`bookingRef`; never retry an unknown booking outcome as though the transport had made it safe.
@@ -356,14 +473,17 @@ outbox, and support operations.
| --- | --- |
| `charts()` | `list` `listAll` `create` `retrieve` `update` `delete` `copy` `archive` `unarchive` `publish` |
| `templates()` | `instantiateTemplate` |
-| `events()` | `list` `listAll` `create` `retrieve` `retrieveConfigurationBinding` `updateConfigurationBinding` `update` `delete` `updateChart` `close` `reopen` `archive` `retrieveHoldTtl` `updateHoldTtl` `listTicketReleases` `updateTicketReleases` `closeTicketRelease` `retrieveReport` `retrieveLog` |
+| `events()` | `list` `listAll` `create` `retrieve` `retrieveConfigurationBinding` `updateConfigurationBinding` `update` `delete` `updateChart` `close` `reopen` `archive` `retrieveHoldTtl` `updateHoldTtl` `listTicketReleases` `updateTicketReleases` `closeTicketRelease` `retrieveReport` `retrieveLog` `retrieveEventBuyerCheckout` `replaceEventBuyerCheckout` `retrieveEventPaymentGateway` `replaceEventPaymentGateway` `retrieveEventSalesReadiness` `preflightEventSales` `transitionEventSales` `retrieveEventBookingFee` `replaceEventBookingFee` `listEventDiscountCodes` `createEventDiscountCode` `updateEventDiscountCode` `endEventDiscountCode` `deleteEventDiscountCode` |
+| `eventSeries()` | `createEventSeries` `listEventSeries` `retrieveEventSeries` `addEventSeriesDates` `updateEventSeries` |
+| `orders()` | `listOrders` `retrieveOrder` `listOrderTickets` `listEventOrders` `retrieveEventOrder` `exportEventOrdersCsv` `refundEventOrder` `cancelEventOrder` `resendEventOrderTickets` |
+| `holders()` | `listCustomers` `retrieveHolder` `updateHolder` `revokeHolderSessions` `listHolderSeasons` `listHolderTickets` `retrieveHolderTicket` `createHolderTransfer` `listHolderTransfers` `cancelHolderTransfer` `acceptHolderTransfer` `createHolderReturn` `createHolderRenewalCheckout` `declineHolderRenewalOffer` |
| `channels()` | `list` `create` `update` `updateAssignments` `listAllocation` `retrieveAccessPreview` `retrieveReport` `pause` `unpause` `archive` `createBuyerAccessSession` `listBuyerAccessSessions` `revokeBuyerAccessSession` |
| `inventory()` | `hold` `holdBestAvailable` `bookBestAvailable` `extendHold` `retrieveHold` `release` `book` `bookLabels` `boxOfficeBook` `unbook` `block` `unblock` `unblockAll` `retrieveAvailability` `updateAvailability` `listBookings` `retrieveBooking` |
| `sessions()` | `createManageSession` `revokeManageSession` `createDesignerSession` `revokeDesignerSession` |
| `webhooks()` | `list` `create` `update` `delete` `listDeliveries` |
| `workspaces()` | `list` `create` `retrieve` `update` |
| `performanceGroups()` | `list` `create` `retrieve` `delete` `activate` `close` `retrieveLifecycle` `createBuyerAccessSession` `listBuyerAccessSessions` `revokeBuyerAccessSession` `retrieveHold` `bookHold` `retrieveBooking` |
-| `seasons()` | 48 operations for catalogue and Plan lifecycle, sales windows, buyer access and booking, holder imports, renewals, occurrence amendments, reports, audit, outbox, and support export |
+| `seasons()` | 87 operations for catalogue and Plan lifecycle, performances, package prices, sales windows, checkout tests, buyer access and booking, holders and holder imports, Season orders, renewals, hosted renewals and renewal checkouts, occurrence returns and amendments, bulk refunds, lapsed offer releases and jobs, reports and CSV exports, audit, outbox, and support export |
Full reference: [SeatLayer Java server SDK guide](https://docs.seatlayer.io/server-sdk/java/)
diff --git a/pom.xml b/pom.xml
index da7ecae..2b1d988 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.seatlayer
seatlayer-java
- 0.8.0
+ 0.9.0
jar
SeatLayer Java Seat Booking and Reserved Seating SDK
diff --git a/src/main/java/io/seatlayer/EventListOptions.java b/src/main/java/io/seatlayer/EventListOptions.java
index 6976ee5..ce2d8e3 100644
--- a/src/main/java/io/seatlayer/EventListOptions.java
+++ b/src/main/java/io/seatlayer/EventListOptions.java
@@ -1,15 +1,39 @@
package io.seatlayer;
-/** Filters and paging for {@link Events#list}. */
+/**
+ * Filters and paging for {@link Events#list}.
+ *
+ * @param workspaceId the workspace to list, or {@code null} for the caller's
+ * @param externalRef only the event with this caller-owned reference, or {@code null}
+ * @param limit the page size, or {@code null} for the default
+ * @param cursor the cursor from the previous page, or {@code null} to start
+ * @param counts whether to include live availability counts
+ * @param seriesKey only the dates of this event series, or {@code null}
+ */
public record EventListOptions(
- String workspaceId, String externalRef, Integer limit, String cursor, boolean counts) {
+ String workspaceId, String externalRef, Integer limit, String cursor, boolean counts,
+ String seriesKey) {
+
+ /**
+ * The options without a series filter, as before {@code seriesKey} was added.
+ *
+ * @param workspaceId the workspace to list, or {@code null} for the caller's
+ * @param externalRef only the event with this caller-owned reference, or {@code null}
+ * @param limit the page size, or {@code null} for the default
+ * @param cursor the cursor from the previous page, or {@code null} to start
+ * @param counts whether to include live availability counts
+ */
+ public EventListOptions(
+ String workspaceId, String externalRef, Integer limit, String cursor, boolean counts) {
+ this(workspaceId, externalRef, limit, cursor, counts, null);
+ }
public static Builder builder() {
return new Builder();
}
EventListOptions withCursor(String next) {
- return new EventListOptions(workspaceId, externalRef, limit, next, counts);
+ return new EventListOptions(workspaceId, externalRef, limit, next, counts, seriesKey);
}
public static final class Builder {
@@ -19,6 +43,7 @@ public static final class Builder {
private String cursor;
// Most callers of a single page want counts; listAll flips this off.
private boolean counts = true;
+ private String seriesKey;
public Builder workspaceId(String value) {
this.workspaceId = value;
@@ -47,8 +72,19 @@ public Builder counts(boolean value) {
return this;
}
+ /**
+ * Lists only the dates of one event series.
+ *
+ * @param value the event series key
+ * @return this builder
+ */
+ public Builder seriesKey(String value) {
+ this.seriesKey = value;
+ return this;
+ }
+
public EventListOptions build() {
- return new EventListOptions(workspaceId, externalRef, limit, cursor, counts);
+ return new EventListOptions(workspaceId, externalRef, limit, cursor, counts, seriesKey);
}
}
}
diff --git a/src/main/java/io/seatlayer/EventSeries.java b/src/main/java/io/seatlayer/EventSeries.java
new file mode 100644
index 0000000..a4dc896
--- /dev/null
+++ b/src/main/java/io/seatlayer/EventSeries.java
@@ -0,0 +1,117 @@
+package io.seatlayer;
+
+import static io.seatlayer.SeatLayerHttpClient.body;
+import static io.seatlayer.SeatLayerHttpClient.encode;
+
+import java.util.Map;
+
+/**
+ * Event series: many dated events planned from one schedule and changed together.
+ *
+ * A series is addressed by its SeatLayer event key.
+ */
+public final class EventSeries {
+
+ private final SeatLayerHttpClient http;
+
+ EventSeries(SeatLayerHttpClient http) {
+ this.http = http;
+ }
+
+ private static String path(String eventKey, String suffix) {
+ return "/v1/event-series/" + encode(eventKey) + suffix;
+ }
+
+ /**
+ * Plans an event series from a schedule, or makes it as a job.
+ *
+ *
Header replay: the same idempotency key is reused on every retry. The API answers
+ * 202 when the dates are made as a job. A series from an event that never started and was
+ * given up answers {@code 409 create_abandoned} for that key every time: send the request
+ * again with a new idempotency key.
+ *
+ *
Every date carries the series name as its name. Give {@code name} and {@code chartKey},
+ * or {@code fromEventKey}: an event you already set up becomes the first date under its own
+ * key, and every other date is a copy of it (floor plan, prices, checkout, poster and its own
+ * seat blocks, none of its orders, holds or sales). The series takes the event's name, zone
+ * and floor plan.
+ *
+ * @param params the request body: {@code name}, {@code chartKey} and {@code schedule}, or
+ * {@code fromEventKey} and {@code schedule}, plus any optional fields such as {@code dryRun}
+ * @param idempotencyKey a stable key, or {@code null} to generate one
+ * @return the decoded response
+ */
+ public Map createEventSeries(Map params, String idempotencyKey) {
+ return http.postWithHeaderReplay("/v1/event-series", params, idempotencyKey);
+ }
+
+ /**
+ * Lists the first page of event series.
+ *
+ * @return the decoded response
+ */
+ public Map listEventSeries() {
+ return listEventSeries(null, null);
+ }
+
+ /**
+ * Lists event series. Null arguments are not sent.
+ *
+ * @param limit the page size, or {@code null} for the server default
+ * @param cursor the cursor from the previous page, or {@code null}
+ * @return the decoded response
+ */
+ public Map listEventSeries(Integer limit, String cursor) {
+ return http.get("/v1/event-series", body("limit", limit, "cursor", cursor));
+ }
+
+ /**
+ * Retrieves an event series, its dates and its job.
+ *
+ * @param eventKey the series' event key
+ * @return the decoded response
+ */
+ public Map retrieveEventSeries(String eventKey) {
+ return http.get(path(eventKey, ""));
+ }
+
+ /**
+ * Adds dates to an event series, copied from its first date.
+ *
+ * Header replay: the same idempotency key is reused on every retry.
+ *
+ * @param eventKey the series' event key
+ * @param params the request body: one of {@code schedule}, {@code dates}, or
+ * {@code retryFailed: true} to make again every date that failed to be made (up to 100;
+ * {@code 422 nothing_to_retry} when none did, {@code 409 series_busy} while another change
+ * runs)
+ * @param idempotencyKey a stable key, or {@code null} to generate one
+ * @return the decoded response
+ */
+ public Map addEventSeriesDates(
+ String eventKey, Map params, String idempotencyKey) {
+ return http.postWithHeaderReplay(path(eventKey, "/dates"), params, idempotencyKey);
+ }
+
+ /**
+ * Changes the name, prices or sales of every upcoming date in the series.
+ *
+ * {@code prices} takes {@code categories}: only the categories whose price changes (for a
+ * tiered category, only the tiers sent). Every price left out keeps each date's own value.
+ *
+ *
{@code sales: "on"} never opens a date its season cancelled: that date is a failed item
+ * of the job ({@code season_date_cancelled}), counted in the job's {@code failed} but not in
+ * {@code failedDates}, which are the dates that could not be made.
+ *
+ *
Header replay: the same idempotency key is reused on every retry.
+ *
+ * @param eventKey the series' event key
+ * @param params the request body: any of {@code name}, {@code prices} and {@code sales}
+ * @param idempotencyKey a stable key, or {@code null} to generate one
+ * @return the decoded response
+ */
+ public Map updateEventSeries(
+ String eventKey, Map params, String idempotencyKey) {
+ return http.mutationWithHeaderReplay("PATCH", path(eventKey, ""), params, idempotencyKey);
+ }
+}
diff --git a/src/main/java/io/seatlayer/Events.java b/src/main/java/io/seatlayer/Events.java
index d0fde29..45c40dd 100644
--- a/src/main/java/io/seatlayer/Events.java
+++ b/src/main/java/io/seatlayer/Events.java
@@ -32,6 +32,7 @@ public Page