@sceneinfrastructure/storefront-api
v0.7.0
Published
Typed SDK and oRPC contract for the Mesh public Storefront API
Maintainers
Readme
@sceneinfrastructure/storefront-api
Typed SDK and oRPC contract for Mesh public Storefront API integrations.
pnpm add @sceneinfrastructure/storefront-api @sceneinfrastructure/public-types @orpc/client @orpc/contract @orpc/openapi-client zodimport { createStorefrontApiClient } from '@sceneinfrastructure/storefront-api/client'
const storefront = createStorefrontApiClient({
baseUrl: process.env.MESH_PUBLIC_API_BASE_URL!,
apiKey: process.env.MESH_SCENE_API_KEY!,
})
const { events } = await storefront.listEvents({
sceneId: process.env.MESH_SCENE_ID!,
})listEvents can also narrow the scene event feed server-side:
const { events } = await storefront.listEvents({
sceneId: process.env.MESH_SCENE_ID!,
status: 'scheduled',
eventIds: ['evt_example'],
eventType: 'RSVP',
collaboratorGroupIds: ['scg_partner_team'],
})eventIds and collaboratorGroupIds match any ID in the provided list, and
all provided filters are combined. Collaborator group filtering is scoped to
the requested sceneId.
The optional @sceneinfrastructure/storefront-api/react-query subpath uses
@orpc/tanstack-query. Install it only if you want oRPC's TanStack Query
helpers; otherwise wrap the typed client with your own useQuery calls.
What the public read endpoints expose
The public read endpoints only return events that are
state = 'published', visibility = 'public', and not archived. Drafts,
publishing rows, archived rows, and private rows are filtered out at the
read layer.
Each event also carries:
acceptingRegistration: boolean— whenfalse, every tier is reported asisActive: false.display: { headline, dateLabel, shortDateLabel, venueLabel, imageAlt, accentLabel, numberLabel }— storefront-ready labels for cards, event detail headers, and checkout summaries.location: { name, address, formattedAddress, kind, url } | null— derived from the V2event.locationJSON when present, with a fallback to V1event.address.
Each tier carries:
display: { group, sortOrder, subtitle, visible, defaultSelected }— admin-defined ticket group label and ordering, a storefront subtitle, visibility, and a default selection hint so storefronts don't need to infer groups or first-choice tiers from labels.price.formattedandallInclusivePrice.formatted— canonical USD display labels alongside numeric USD and integer USDC values.quantity: { label, remainingNumber, ... }— storefront-ready inventory labels and safe numeric remaining quantities when available.relationships: { requiredParentTierId }— when non-null, the tier is an add-on that must be purchased with an eligible primary ticket. Checkout accepts the exact referenced parent tier, except for Mesh's internal "any primary" add-on group where any primary event ticket can satisfy the relationship.restrictions: { maxQuantityPerOrder, requiresAccessCode }— same surface as before.schedule: { startTime, endTime, timezone }andvalidityWindow: { validFrom, validUntil, isActive }— public sale and ticket-validity windows for storefront presentation.
POST /v1/cart-url accepts multi-item carts and returns a checkout URL
that encodes every item as repeated saleKeyId/quantity query
parameters. The endpoint:
- Aggregates duplicate
saleKeyIdlines server-side before validation, so splitting an order into multiple identical line items cannot bypass availability or add-on parent-quantity checks. - Sorts primary tiers before add-ons in the emitted URL so the hosted storefront's preselect always sees the parent before its children regardless of input ordering.
It enforces these rules server-side:
- 409 Conflict when an add-on tier is included without an eligible primary
ticket in the same cart (
requiredParentTierIdnot satisfied by the exact parent tier or Mesh's internal "any primary" add-on group). - 409 Conflict when an add-on tier's quantity exceeds the eligible primary ticket quantity in the same cart.
- 409 Conflict when a tier is sold out or requested quantity exceeds remaining availability (after duplicate-line aggregation).
- 422 Validation Failed when the cart includes more than one distinct primary ticket tier. The current hosted storefront state model supports only one primary tier (with optional add-ons). Pass a single primary tier per cart URL.
- 422 Validation Failed when the sum of primary ticket quantities
exceeds
event.ticketOrderLimit(treated as "no limit" when non-positive). Add-on quantities ride along with their parent and are not counted against the per-event order limit (they are independently capped at the parent quantity).
Reserved and RSVP order workflow
Reserved orders are a server-side checkout alternative for partners that
collect or attest payment outside Mesh, such as Blackbird Pay. Use them from a
trusted backend only; the scene API key and Idempotency-Key must not be sent
from browser code.
The flow is:
POST /v1/events/{eventId}/orderswithIdempotency-Keyto reserve inventory and receive an order inpayment_pendingstatus.- Complete the external payment with the provider.
POST /v1/orders/{orderId}/confirmwith the external payment attestation.GET /v1/orders/{orderId}to poll or reconcile the canonical order status and issued ticket.
Create-order requests include purchaser contact, payment handoff details, an
optional reservation TTL, and either the legacy single-item shape
(slotId/quantity) or a multi-item items array. Each items entry uses the
public slot identifier returned by Mesh plus its quantity. Multi-item reserved
orders reserve, price, and fulfill every line item atomically; add-on tiers must
include an eligible primary ticket in the same order and cannot exceed the
eligible primary quantity. Create, confirm, and get responses include items so partners
can reconcile the exact session/add-on allocation. They also include
cart.breakdown, with subtotal, itemized fees (processingFee,
protocolFee, vendorFee, referrerFee, total), itemized taxes
(salesTax, total), and final total in USD minor units. Confirm requests
currently support the blackbird_pay external provider and require amount,
currency, external payment ID, paid timestamp, and paid status. Confirmed
orders return the ticket details when fulfillment succeeds; orders may also
remain fulfillment_pending, fail, expire, or be fetched later for
reconciliation.
For RSVP events with no payment component, use the same create-order endpoint
with type: "rsvp" and omit payment. Mesh validates that the event is an RSVP
event and that the selected slots price to zero, then immediately starts ticket
fulfillment. The create response is the canonical order shape with type:
"rsvp" and a status such as fulfillment_pending or confirmed; poll
GET /v1/orders/{orderId} when fulfillment is pending.
Always send a stable Idempotency-Key for create-order retries. Reusing the
same key for the same logical order is safe; generating a new key for every
retry can create duplicate reservations.
Named request/response types
@sceneinfrastructure/storefront-api exports named TypeScript aliases
for every endpoint so consumers don't need to derive output types from
the client or z.infer on schemas:
import type {
ListEventsOutput,
ListEventTiersOutput,
ListEventPricesOutput,
CreateCartUrlInput,
CreateCartUrlOutput,
CreateOrderInput,
CreateOrderOutput,
ConfirmOrderInput,
ConfirmOrderOutput,
GetOrderOutput,
StorefrontApiEvent,
StorefrontApiEventDisplay,
StorefrontApiEventLocation,
StorefrontApiEventType,
StorefrontApiPrice,
StorefrontApiTier,
StorefrontApiTierDisplay,
StorefrontApiTierRelationships,
StorefrontApiTierRestriction,
StorefrontApiOrderItem,
StorefrontApiOrderSlot,
StorefrontApiOrderStatus,
StorefrontApiOrderTicket,
} from '@sceneinfrastructure/storefront-api'The schemas (listEventsOutputSchema, publicApiTierSchema, etc.) and
typed client (@sceneinfrastructure/storefront-api/client) remain
available unchanged.
Agent skill
If you are using an AI coding agent, install the Mesh Storefront skill for API/SDK setup guidance, Next.js server-only usage patterns, required env vars, and OpenAPI fallback examples:
npx skills add https://api.sceneconstruction.xyzThe installer discovers the skill from
https://api.sceneconstruction.xyz/.well-known/agent-skills/index.json.
