Shop
Writing a custom frontend
The Shop allows you to write a custom frontend to sell your tickets.
To implement a storefront similar to shop.eventjet.at/[shop-slug], follow these basic steps:
-
Retrieve all events and event groups available in your shop. If your shop sells tickets for a single event, you can skip to Step 2.
You need the slug of the shop to fetch the events. You can find it in the Eventjet backend under "My Shop". Don't worry if you change the slug later; previous slugs will still work, although the
slugfield always resolves to the current slug.query GetEvents($shopSlug: ID!, $locale: String!) { shop(slug: $shopSlug) { events { ... Event } eventGroups { name(locale: $locale) # Name of the event group in the specified locale events { ... Event } } } } fragment Event on ShopEvent { id # The ID of the event. You will need this to fetch the event details. name(locale: $locale) # The name of the event in the given locale earliestStart # The start of the event }query GetEvents($shopSlug: ID!, $locale: String!) { shop(slug: $shopSlug) { events { ... Event } eventGroups { name(locale: $locale) # Name of the event group in the specified locale events { ... Event } } } } fragment Event on ShopEvent { id # The ID of the event. You will need this to fetch the event details. name(locale: $locale) # The name of the event in the given locale earliestStart # The start of the event } -
Fetch the list of available ticket types for an event.
query GetEvent($shopSlug: ID!, $eventId: ID!, $locale: Locale!) { shop(slug: $shopSlug) { event(id: $eventId) { items { id # The ID of the ticket type. You will need this to add tickets to the cart. name(locale: $locale) # The name of the ticket type in the given locale unavailabilityReason(locale: $locale) # Non-null when the item is sold out or not yet on sale price { amount currency { code } } } } } }query GetEvent($shopSlug: ID!, $eventId: ID!, $locale: Locale!) { shop(slug: $shopSlug) { event(id: $eventId) { items { id # The ID of the ticket type. You will need this to add tickets to the cart. name(locale: $locale) # The name of the ticket type in the given locale unavailabilityReason(locale: $locale) # Non-null when the item is sold out or not yet on sale price { amount currency { code } } } } } }When
unavailabilityReasonis non-null, the item cannot be purchased. Display the reason string to the user and disable any "Add to cart" controls for that item.Note: Full documentation for seat tickets is not yet available, but you can explore
ShopEvent.seatmapsfor more details. -
Use the
setCartItemQuantitymutation to add tickets to the cart. You can also use this mutation to increase or decrease the number of tickets in the cart or to remove all tickets of a certain type by setting the quantity to 0.To add the first ticket to the cart, just pass the
cartIdasnull. The mutation will create a new cart and resolve to it, giving you the ID of the cart. You can use this ID to modify the cart later.mutation AddToCart($shopSlug: ID!, $itemId: ID!, $quantity: Int!, $cartId: ID) { setCartItemQuantity( shopSlug: $shopSlug, # From Shop.slug (See step 1) itemId: $itemId, # From ShopItem.id (See step 2) quantity: $quantity, # The number of tickets the user wants to buy cartId: $cartId # The ID of the cart. Pass null to create a new cart. ) { cart { id # The ID of the cart. Pass this to other cart-related queries and mutations. items { name quantity } } error # Non-null when the operation failed. Contains an error code (e.g. NOT_ENOUGH_AVAILABLE). } }mutation AddToCart($shopSlug: ID!, $itemId: ID!, $quantity: Int!, $cartId: ID) { setCartItemQuantity( shopSlug: $shopSlug, # From Shop.slug (See step 1) itemId: $itemId, # From ShopItem.id (See step 2) quantity: $quantity, # The number of tickets the user wants to buy cartId: $cartId # The ID of the cart. Pass null to create a new cart. ) { cart { id # The ID of the cart. Pass this to other cart-related queries and mutations. items { name quantity } } error # Non-null when the operation failed. Contains an error code (e.g. NOT_ENOUGH_AVAILABLE). } }Always check
SetCartItemQuantityResult.errorbefore using the cart. When it is non-null, the cart was not modified and the response will also include a GraphQL error on theSetCartItemQuantityResult.cartfield. The value is an error code (e.g.NOT_ENOUGH_AVAILABLE) — map it to a user-facing message in your frontend. -
To place an order, you need to attach the customer's data to the cart first. To find out which data you need to provide, use the
checkoutFormfield.query GetCheckoutForm($shopSlug: ID!, $locale: String!) { shop(slug: $shopSlug) { checkoutForm { elements { label(locale: $locale) ...LeafFormElement ...on CompoundFormElement { elements { ...LeafFormElement } } } } } } fragment LeafFormElement on FormElement { name label(locale: $locale) required ... on ChoiceFormElement { multiple choices { value label(locale: $locale) } } }query GetCheckoutForm($shopSlug: ID!, $locale: String!) { shop(slug: $shopSlug) { checkoutForm { elements { label(locale: $locale) ...LeafFormElement ...on CompoundFormElement { elements { ...LeafFormElement } } } } } } fragment LeafFormElement on FormElement { name label(locale: $locale) required ... on ChoiceFormElement { multiple choices { value label(locale: $locale) } } } -
Use the
applyCustomerDataToCartmutation to attach the customer's data to the cart.Each
FormValueInputmust have aFormValueInput.keyand aFormValueInput.value. TheFormValueInput.keymust match theFormElement.nameof aFormElementfrom thecheckoutFormfield (see step 4). Elements nested in aCompoundFormElementmust be prefixed with theCompoundFormElement.nameof theCompoundFormElementand a dot (e.g.address.postal_code). Values for Boolean elements must bebool:1orbool:0.mutation ApplyCustomerDataToCart($cartId: ID!, $data: [FormValueInput!], $locale: String!) { applyCustomerDataToCart(input: {cartId: $cartId, data: $data}) { cart { id customerDataIsValid # true when all required fields are present and valid } validation { errors { fieldName # The key of the invalid field (e.g. "email", "address.postal_code") message(locale: $locale) # User-facing error message } } } }mutation ApplyCustomerDataToCart($cartId: ID!, $data: [FormValueInput!], $locale: String!) { applyCustomerDataToCart(input: {cartId: $cartId, data: $data}) { cart { id customerDataIsValid # true when all required fields are present and valid } validation { errors { fieldName # The key of the invalid field (e.g. "email", "address.postal_code") message(locale: $locale) # User-facing error message } } } }Check
validation.errorsafter each call and display any field-level messages next to the relevant inputs. Do not callplaceOrder(step 8) untilCart.customerDataIsValidistrue. -
Most shops do not require ticket holder data. Check
Cart.ticketHolderFormsto determine if this step is needed — if the returned list is empty, skip to step 7.When ticket holder data is required,
ticketHolderFormsreturns one form entry per ticket in the cart that needs holder data. (For example, if the user has two tickets that both require holder data, two entries are returned, each with a uniqueTicketHolderForm.key.) Display the form fields for each entry and collect the required information from the attendee.query GetTicketHolderForms($cartId: ID!, $locale: String!) { cart(id: $cartId) { ticketHolderForms { key name(locale: $locale) elements { label(locale: $locale) ...LeafFormElement ...on CompoundFormElement { elements { ...LeafFormElement } } } } } } fragment LeafFormElement on FormElement { name label(locale: $locale) required ... on ChoiceFormElement { multiple choices { value label(locale: $locale) } } }query GetTicketHolderForms($cartId: ID!, $locale: String!) { cart(id: $cartId) { ticketHolderForms { key name(locale: $locale) elements { label(locale: $locale) ...LeafFormElement ...on CompoundFormElement { elements { ...LeafFormElement } } } } } } fragment LeafFormElement on FormElement { name label(locale: $locale) required ... on ChoiceFormElement { multiple choices { value label(locale: $locale) } } }Then submit the holder data with
applyTicketHolderDataToCart. Pass oneTicketHolderDataInputper form entry, using the form'sTicketHolderForm.key. Thedataarray follows the same format as step 5.mutation ApplyTicketHolderData($cartId: ID!, $ticketHolders: [TicketHolderDataInput!]!) { applyTicketHolderDataToCart(input: { cartId: $cartId, ticketHolders: $ticketHolders, }) { cart { id } } }mutation ApplyTicketHolderData($cartId: ID!, $ticketHolders: [TicketHolderDataInput!]!) { applyTicketHolderDataToCart(input: { cartId: $cartId, ticketHolders: $ticketHolders, }) { cart { id } } } -
To query the available payment methods, use the
Cart.paymentMethodsfield.query GetPaymentMethods($cartId: ID!, $locale: Locale!) { cart(id: $cartId) { paymentMethods { key name description(locale: $locale) # Optional extra info to display alongside the method logo # SVG data URI, suitable for an <img> src } } }query GetPaymentMethods($cartId: ID!, $locale: Locale!) { cart(id: $cartId) { paymentMethods { key name description(locale: $locale) # Optional extra info to display alongside the method logo # SVG data URI, suitable for an <img> src } } } -
Use the
placeOrdermutation to place the order.mutation PlaceOrder($cartId: ID!, $paymentMethodKey: ID) { placeOrder(input: { cartId: $cartId, paymentMethodKey: $paymentMethodKey, # One of the keys from the `paymentMethods` field (see step 7) }) { redirectUrl # Redirect the user here to complete payment (see step 9) order { id # Always present — persist this before redirecting to use with Query.orderStatus } } }mutation PlaceOrder($cartId: ID!, $paymentMethodKey: ID) { placeOrder(input: { cartId: $cartId, paymentMethodKey: $paymentMethodKey, # One of the keys from the `paymentMethods` field (see step 7) }) { redirectUrl # Redirect the user here to complete payment (see step 9) order { id # Always present — persist this before redirecting to use with Query.orderStatus } } } -
Redirect the user to the URL resolved by the
placeOrdermutation. This URL will take the user to the payment provider's website where they can complete the payment.After the payment is completed, the user will be redirected to a confirmation page on shop.eventjet.at. There is currently no way to customize this page or to redirect the user back to your website.
To check the order status programmatically, use
Query.orderStatuswith the order ID returned byplaceOrder. This resolves order details such asOrderStatus.isPaid,orderNumber, and ticket download links.query GetOrderStatus($orderId: ID!) { orderStatus(orderId: $orderId) { isPaid orderNumber orderTotal { amount currency { code } } downloads { title url } } }query GetOrderStatus($orderId: ID!) { orderStatus(orderId: $orderId) { isPaid orderNumber orderTotal { amount currency { code } } downloads { title url } } }
Here's a list of root fields you can use to interact with the shop:
Query.cartQuery.checkEmailQuery.orderStatusQuery.seatmapQuery.shopMutation.addSeatToCartMutation.applyCodeToNewCartMutation.applyCustomerDataToCartMutation.applyDiscountCodeMutation.applyTicketHolderDataToCartMutation.attributeCartMutation.consumeCartFlashMessagesMutation.extendCartExpirationMutation.placeOrderMutation.removeDiscountCodeFromCartMutation.removeItemFromCartMutation.removeSeatFromCartMutation.setCartItemQuantityMutation.setCartVolumeQuantities
Fields
| Field | Description | Type |
|---|---|---|
acceptsDiscountCodes | Indicates whether the shop accepts discount codes. | Boolean |
checkoutAgreements | [ CheckoutAgreement! ]! | |
checkoutForm | Form! | |
customerSupportEmail | Email | |
event | ShopEvent | |
eventGroup | ShopEventGroup | |
eventGroups | [ ShopEventGroup! ]! | |
events | [ ShopEvent! ]! | |
logo | Image | |
marketingCode | String | |
name | String! | |
paymentMethods | [ PaymentMethod ] | |
slug | ID! | |
themeColor | Color |