{{op.method}} /api{{api.path}}
{{op.summary}}
Permissions: {{access}} ({{translatePermission(access)}})
Addons: {{module}}
Requires a logged in session (cookie)
Minimal version: {{op.version}}
Parameters
Returns: {{op.responseClass.startsWith('array of') ? 'array of ' : ''}}{{getModelName(op.responseClass)}}
Returns: {{op.responseClass}}

Addons

An Addon is something which extends the Zoezi product with additional functionality. It can be anything from a small widget displaying number of active members to an entire entry system integration. A supplier is the company behind an addon.

Signing up

To register as a supplier, go to the Zoezi developer portal: https://developer.zoezi.se/

After successful registration a test system will be created. That test system can be used to see the addons in action during development.

A supplier can add several developers who are allowed to login and create and manage addons. Using the main supplier account, developer accounts can be added and removed. Development can also be done with the main supplier account.

Zoezi developer portal

In the developer portal a supplier and its developers can:

  • Create addons
  • See usage and sales statistics for published addons
  • Write functions hosted by Zoezi, directly in the browser
  • See logs of function execution
  • Add and remove developer accounts

Types of addons

The following can be built with addons:
  • Back office, backend addons
    This can be an addon which acts in response to a webhook firing. For example an addon which sets a particular Status on a member when it's created. Or it can be an addon which gets external input and feeds it into the system, like an Entry integration
  • Staff dashboard widget
    A widget (iframe) with any content which will be displayed in a staff dashboard
  • Customer card widget
    A widget (iframe) with any content which will be displayed in the Staff app when viewing a customer
  • Staff card widget
    A widget (iframe) with any content which will be displayed in the Staff app when viewing a staff

Development

When writing a widget or a webhook, there are two ways in which Zoezi will call that widget or webhook.

  • Using a built in function hosted by Zoezi - edited directly in the browser. Most convenient and quick solution.
  • Providing a URL. That function needs to be hosted by the supplier.

Welcome to Zoezi's API documentation

Basic access or Addon

There are two ways of integrating with Zoezi. The most basic approach: using the public and member-API's, or the more advanced one, allowing access to all of the Zoezi API's and possibility to write widgets, by writing an Addon.

Authentication

Every integration must authenticate itself. Every integration has an API key for that purpose. Authentication is done using the HTTP Authorization header. Example:

curl -H "Authorization: Zoezi {{key ? key : 'ABCDEF123ABC'}}" https://{{getHost()}}/api/public/workout/get/all?fromDate=2019-01-01&toDate=2019-12-31
              

Versioning

The API is versioned. The version is put in the URL path in the following way for {{version}}:

https://{{getHost()}}/api/v{{version}}/public/workout/get/all?fromDate=2019-01-01&toDate=2019-12-31
              

If the version part of the URL is omitted, the latest version of the API will be used. Beware that it may break, when newer versions of the API is released. To use the latest version of the API:

https://{{getHost()}}/api/public/workout/get/all?fromDate=2019-01-01&toDate=2019-12-31
              

Permissions

In Zoezi there is a concept of Permission. An integration with no permissions assigned cannot call any API's which require any permissions. Only public methods are available to those integrations. If an addon has the Permission Show payments it can use the method /api/payment/get/

Logging

Inside Zoezi all actions are logged. It's possible to see which integration did what, and which user did what. If a user logs in using an addon, both the addon and the user will be shown.

Stats

Number of API methods: {{stats.num_apis}}
Number of fully documented methods: {{stats.num_fulldoc}} ({{Math.round(100.0 * stats.num_fulldoc / stats.num_apis)}}%)

Widgets

A widget is embedded inside the system using an Iframe. There are three types of widgets:

  • Staff dashboard widget
    A widget (iframe) with any content which will be displayed in a staff dashboard
  • Customer card widget
    A widget (iframe) with any content which will be displayed in the Staff app when viewing a customer
  • Staff card widget
    A widget (iframe) with any content which will be displayed in the Staff app when viewing a staff

There are three ways to create a widget.

  • Zoezi hosted widget
    A function which returns HTML. Can be written in NodeJS or Python and is hosted by Zoezi
  • Externally hosted widget
    Provide a https address to an externally hosted page
  • Vue 3 component
    A component written in vue3

Zoezi hosted widget

The following information is sent in the data parameter (first parameter) to the function: node.js example of a customer card widget showing the customer name in bold text:

Externally hosted widget

The following parameters are sent using query parameters:

Vue 3 component

Vue 3 components are very basic and basically only has one dependency which is Vue3. A minimal interface exists as this.$api or window.$zoeziapi.

ZoeziApi

get(url. args, options) post(url, data, args) subscribe(options) callStaffApp(module, fn) Settings are passed into the component's props In addition to that a prop called zoezi_settings is set.

Calling the parent staff application

It's possible to use functionality in the parent staff application. Dialogs can be opened, it's possible to navigate to another page and so on. It's also possible to subscribe to websocket events, sharing the parent websocket connection.

Example where a subscription to listen to workout changes is setup:

List of functions in the $rootScope module:
getData(property) Gets data, for example: members, trainingcardtypes, usergroups, roles, memberstatuses, paymentmethods, entries logout() Logs out staff switchToMemberPage Navigates away from admin page and goes to /member gotoCustomer(id) Navigates to customer page, /customer/show/:id gotoStaff(staffObject) Navigates to staff page or resource page showWorkout(workoutObject) {id} Brings up a modal showing a workout showGroup(groupObject) {id} Shows group dialog showMatch(matchObject) (full match object) Shows match dialog showRBooking(rbObject) {id} Shows resource booking dialog showCombo(options) Shows dialog for adding training card options: { customer: object; workout: object; membership: bool; rbslot: resource booking slot {service, ...} minimal: bool; validFromDate: Date; group: object; trainingcard: object cardId: string; supplier: string; callback: function; } downloadElectron Shows dialog for downloading proxyapp about Show about dialog showHelp Show help dialog previewTemplate(mailing, modalTitle) Shows template preview dialog. mailing is result from /api/mailing/get removeWorkout(workoutObject) {id} Shows workout remove dialog addStaff(gotoStaff) Shows add staff dialog. Go to staff after done if gotoStaff is true addCustomer Shows dialog to add customer addTask Shows dialog to add task addWorkout Shows dialog to add workout addSystemTag Shows dialog to add a system tag toastHidden Hides toast. (Small info message) showInfo Shows a toast message for 10s hideSupportChatForPage Hides the Zoezi support chat
List of functions in the modalUtils module:
closeAllModals() closes all modals forceCloseAllModals Closes all modals even if there are changes closeTop Closes the top modal

Webhooks

Webhooks is a way to get notified of events occurring. A customer account being created, a payment being paid, an entry being made or a booking being made are some examples of events.

Webhook data for Zoezi hosted function


The event

Webhook data for supplier hosted function

Every webhook request is sent using POST method with body data in JSON format.


The event

Verify origin

For supplier hosted webhooks, the origin should be checked. For Zoezi hosted webhooks, that is not required. Every webhook is configued with a secret. This secret is used to create a checksum which is sent in every webhook request in a header named X-Zoezi-Checksum. This checksum can be used to verify that the webhook originates from Zoezi.

The checksum is created in a way similar to this:

checksum = hmac(secret, request_body, SHA256)

In order to verify the checksum, here is a python example:
Our secret: hello
The body: some data
Calculated checksum: bbabdc400efff57f8a7687ff99000b567a6de4704bd3db608d1a1ca46ed94fd2

Python code:

Websocket

Using websockets it's possible to get live updates to the javascript client when things happens in the system. For a staff card widget for instance, connect to:
wss://{{getHost()}}/api/async?type=staff Here is an example which logs all websocket events in a staff dashboard widget:

Components

Available components

Below, you'll find a compilation of components we've crafted to enable external developers to create their own components with greater ease.

ComponentWrapper
- Embed components that are available through the Flex tool
MediaLibrary
- Upload new images or select from existing ones

ComponentWrapper


MediaLibrary

type: [String] ("image", "video") The type of media to show in the library.
change: [String] The id of the selected image. This value is emitted out of the component.
columns: [Number] How many columns the images should be shown in.
canShow: [Boolean] If images in the grid should be viewed larger when clicked on.

Examples

Checkout component

Here is an example where two items are being sold, one of the first and 7 of the second, not possible to change item count
The result looks like this:

The following props can be sent to the checkout component


The following events can be received from the checkout component:


Example of cancelRules prop

                {
                    canCancel: true,
                    lastCancelTime: DateTime
                    rules: [
                        {time: {value: 1, timeunit: 'week', relative: 'beforestart'}, cost_percent: 50, cost_fixed: 0 },
                        {time: {value: 2, timeunit: 'week', relative: 'beforestart'}, cost_fixed: 100 }
                    ]
                }
                

To buy one resource booking, one item in items prop shall be set to

                  {
                    count: 1
                    extra_person (optional)
                    optional_resource (optional)
                    rbservice_id
                    service (object)
                    reservation (id of reservation)
                    slots: [
                        start
                        end
                        rbservice_id
                        staff_id
                    ],
                    context (optional context),
                    extended_info (answer to questions)
                    tmp_id (in order to link additional products)
                  }