Skip to main content
Two things most venues need and a tier-per-counter model can’t express:
  • One capacity, several prices. Adult and child tickets for the same show share the same 100 places. Selling 60 adults must leave 40 for children, not 100.
  • A venue’s own clock. “On sale Friday at 10:00” means 10:00 where the show is, not where your server or your staff happen to be.
Both are available on the integration API and in @alytegen/sdk 0.6.0. One API key with merchant:read and merchant:write manages all of it.

Shared pools

A pool is a capacity that several general-admission tiers draw on. A pooled tier has no counter of its own: every sale, hold and release moves the pool’s count, and it can never sell more than the pool holds. That guarantee is enforced by the database in one atomic step, the same way as a single tier.
REST: POST /v1/integration/pools, GET /v1/integration/pools?merchantId=…, PATCH /v1/integration/pools/{id}, and poolId on POST /v1/integration/tiers and PATCH /v1/integration/tiers/{id}. Rules worth knowing before you build on them: Seated tiers keep their own seats and cannot draw on a pool.

Venue locations

A location is optional metadata on your shop: a name and an IANA time zone such as Europe/Warsaw. It is not a separate account and does not own inventory; an event works without one.
Event creation with a location is all-or-nothing: if the location changed since you read it, or belongs to another shop, neither the event nor the binding is saved. Versions, not live links. Every edit to a location creates a new version. An event stays pinned to the version it was bound to until you rebind it, so renaming a venue or correcting its time zone never silently moves an existing show. Rebinding or clearing a location never reschedules the event either: startsAt is always an explicit instant. REST: GET|POST /v1/integration/merchants/{id}/locations, PATCH …/locations/{locationId}, GET …/slots/{slotId}, PUT …/slots/{slotId}/location. Stale edits are refused. Every write carries the revision you read. If someone else changed it in between, you get 409 commerce_schedule_conflict: reload and retry. When a sale-window edit depends on the event’s venue time, pass expectedOccurrenceRevision to updateTier so the edit is refused if the venue binding moved since you computed the time.

Reading inventory

inventoryCatalog(merchantId) (GET /v1/integration/merchants/{id}/inventory) returns one consistent snapshot of a shop: offers, base prices, sale windows, the pinned venue of each event, and the live count of every inventory source. Several offers on one pool reference the same source, so you see one counter, not one per price.
  • It is an observation: counts can change a moment later, and capabilities says reserve, quote and purchase are all false. Buying still goes through the normal quote, reserve and confirm flow.
  • Prices are kind: "unit_base" in integer minor units, before fees and tax.
  • Buyer and agent allow-lists are never exposed; an offer only says principalRestricted.
  • A shop larger than 2,000 rows in any relation returns 413 catalog_too_large rather than a partial answer. listLocations has its own 2,000-row bound.

Event creation is strict

POST /v1/integration/events accepts exactly merchantId, title, startsAt (with an explicit offset) and the optional location. Any other field returns 400; it used to be ignored. The SDK and integrations that send only those fields are unaffected.

In the console

Shop owners get the same controls under Inventory: create and edit pools, attach tiers to a pool, create and assign locations, and edit times in the venue’s own zone. Events without a venue are shown and edited in UTC, and labelled so.