Eventjet GraphQL API documentation

Shop

Object

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:

  1. 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 slug field 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
    }
    
  2. 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 unavailabilityReason is 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.seatmaps for more details.

  3. Use the setCartItemQuantity mutation 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 cartId as null. 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.error before using the cart. When it is non-null, the cart was not modified and the response will also include a GraphQL error on the SetCartItemQuantityResult.cart field. The value is an error code (e.g. NOT_ENOUGH_AVAILABLE) — map it to a user-facing message in your frontend.

  4. 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 checkoutForm field.

    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)
        }
      }
    } 
    
  5. Use the applyCustomerDataToCart mutation to attach the customer's data to the cart.

    Each FormValueInput must have a FormValueInput.key and a FormValueInput.value. The FormValueInput.key must match the FormElement.name of a FormElement from the checkoutForm field (see step 4). Elements nested in a CompoundFormElement must be prefixed with the CompoundFormElement.name of the CompoundFormElement and a dot (e.g. address.postal_code). Values for Boolean elements must be bool:1 or bool: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.errors after each call and display any field-level messages next to the relevant inputs. Do not call placeOrder (step 8) until Cart.customerDataIsValid is true.

  6. Most shops do not require ticket holder data. Check Cart.ticketHolderForms to determine if this step is needed — if the returned list is empty, skip to step 7.

    When ticket holder data is required, ticketHolderForms returns 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 unique TicketHolderForm.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 one TicketHolderDataInput per form entry, using the form's TicketHolderForm.key. The data array 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
        }
      }
    }
    
  7. To query the available payment methods, use the Cart.paymentMethods field.

    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
        }
      }
    }
    
  8. Use the placeOrder mutation 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
        }
      }
    }
    
  9. Redirect the user to the URL resolved by the placeOrder mutation. 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.orderStatus with the order ID returned by placeOrder. This resolves order details such as OrderStatus.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:

Fields