API

# API Endpoints

Activity Messenger provides you with a RESTful API returning JSON. All calls must be authenticated. From your back-end, you must pass the API key in the HTTP header. The API key can be obtained by clicking on the menu E-Commerce, and choosing the option API & IFRAME.

X-Activity-Messenger-Api-Key: abc123ABC123qwe456

Note: API keys from a master organization of a franchise or a federation are accepted for any organization in the network.


# Pagination

By default, GET endpoints that return collections are not paginated and limited to 50 items. Pass query string per_page or page to obtain a paginated result. A maximum of 250 items can be returned. A paginated result returns something like this:

GET /api/v1/organization/1234/form_tags?per_page=5
{
  "current_page": 1,
  "data": [
    "QC Waivers",
    "Newsletter"
  ],
  "first_page_url": "https://activitymessenger.com/api/v1/organization/1234/form_tags?page=1",
  "from": 1,
  "last_page": 1,
  "last_page_url": "https://activitymessenger.com/api/v1/organization/1234/form_tags?page=1",
  "next_page_url": null,
  "path": "https://activitymessenger.com/api/v1/organization/1234/form_tags",
  "per_page": 5,
  "prev_page_url": null,
  "to": 2,
  "total": 2
}

# GET /api/v1/organization/{organization}

Retrieve the organization basic information and URL to the Microsite.


# GET /api/v1/organization/{organization}/network

For franchises and federations, retrieves the list of organizations part of the network.


# Messages and templates (newsletters)

In Activity Messenger, newsletters can be published from either a template or a sent message. A published template can be modified whereas a published message cannot. Read this help page to find out more: Newsletters. Use these API endpoints to retrieve all published messages and templates.

# GET /api/v1/organization/{organization}/published_messages

Retrieves a list of all published sent messages ordered by published date (last first).


# GET /api/v1/organization/{organization}/published_templates

Retrieves a list of all published templates ordered by published date (last first).


These endpoints return a list of messages/templates. For example, this template would return the following JSON:

{
    "current_page": 1,
    "data": [
        {
            "id": 27033,
            "name": "Newsletter",
            "subject": "📰 News this month",
            "url": "https://activitymessenger.com/x/cINo4cH",
            "short_url": "https://am.lol/x/cINo4cH",
            "published_at": "2022-09-20T17:59:57.000000Z",
            "created_at": "2022-09-19T18:41:25.000000Z",
            "updated_at": "2022-09-20T17:59:57.000000Z",
            "background_color": "#2E3951",
            "background_image": null,
            "button_color": null,
            "content_background_color": null,
            "blocks": [
                {
                    "type": "hero",
                    "text": null,
                    "image_url": "https://activitymessenger-assets-ca.s3.amazonaws.com/images/a25f134e02fc5b2d26de262bf2adb7ce/0001-24397301835.png",
                    "image_alt": null,
                    "image_cta_url": null,
                    "image_percent": 0.5,
                    "button_url": null,
                    "button_text": null,
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": {
                        "align": "top",
                        "canva_id": "DAE-nUNuIuQ"
                    }
                },
                {
                    "type": "one-column",
                    "text": "<p>Hello <span class=\"placeholder\">{First name}</span></p><p>Lot's is happening this month! Read all about it and thank you for being part of our community!</p>",
                    "image_url": null,
                    "image_alt": null,
                    "image_cta_url": null,
                    "image_percent": 0.5,
                    "button_url": null,
                    "button_text": null,
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": null
                },
                {
                    "type": "image-column",
                    "text": "<h2>Introduction to chess</h2><p>New this month are chess classes for young ones. It is the perfect way for generations to meet and have fun.</p>",
                    "image_url": "https://activitymessenger-assets-ca.s3.amazonaws.com/images/cccce7e7782c6459afe6ea9a86825faa/pexels-photo-5691836.jpeg",
                    "image_alt": null,
                    "image_cta_url": null,
                    "image_percent": 0.5,
                    "button_url": "https://activitymessenger.com/",
                    "button_text": "Learn more",
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": null
                },
                {
                    "type": "column-image",
                    "text": "<h2>Zoom classes</h2><p>Dozens of classes will be held on Zoom. Schedule will be out next week!</p>",
                    "image_url": "https://activitymessenger-assets-ca.s3.amazonaws.com/images/0701f26d3584caa085c84b4b6b7478aa/Classes-now-available.jpg",
                    "image_alt": null,
                    "image_cta_url": null,
                    "image_percent": 0.5,
                    "button_url": "https://activitymessenger.com/",
                    "button_text": "Learn more",
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": null
                },
                {
                    "type": "video-column",
                    "text": "<p>Cat plays with scotch tape</p><p>18 seconds or pure pleasure watching this young cat play with tape</p>",
                    "image_url": "https://activitymessenger-assets-ca.s3.amazonaws.com/video_previews/3dfbbff02f9f0379b81bcc5adbac2484/c/cat-plays-with-scotch-tape-thumb-preview.jpg",
                    "image_alt": "Cat plays with scotch tape",
                    "image_cta_url": "https://am.lol/v/I3drzXe",
                    "image_percent": 0.5,
                    "button_url": "https://am.lol/v/I3drzXe",
                    "button_text": "Watch the video",
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.6666,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": null
                },
                {
                    "type": "spacer",
                    "text": null,
                    "image_url": null,
                    "image_alt": null,
                    "image_cta_url": null,
                    "image_percent": 0.5,
                    "button_url": null,
                    "button_text": null,
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": {
                        "line_color": null,
                        "line_width": 0,
                        "margin_top": "10",
                        "margin_bottom": null,
                        "margin_left_right": null
                    }
                },
                {
                    "type": "video",
                    "text": "<h5>Cat plays with scotch tape</h5><p>18 seconds or pure pleasure watching this young cat play with tape</p>",
                    "image_url": "https://activitymessenger-assets-ca.s3.amazonaws.com/video_previews/f25ff677b79f2cc3ef9677ab8c6bdaa5/c/cat-plays-with-scotch-tape-thumb-preview.jpg",
                    "image_alt": "Cat plays with scotch tape",
                    "image_cta_url": "https://am.lol/v/I3drzXe",
                    "image_percent": 0.5,
                    "button_url": "https://am.lol/v/I3drzXe",
                    "button_text": "Visioner la vidéo",
                    "button_color": null,
                    "button_target": null,
                    "button_protocol": null,
                    "text2": null,
                    "image_url2": null,
                    "image_alt2": null,
                    "image_cta_url2": null,
                    "image_percent2": 0.3333,
                    "button_url2": null,
                    "button_text2": null,
                    "button_color2": null,
                    "button_target2": null,
                    "button_protocol2": null,
                    "meta": null
                }
            ]
        }
    ],
    "first_page_url": "https://activitymessenger.com/api/v1/organization/1234/published_templates?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://activitymessenger.com/api/v1/organization/1234/published_templates?page=1",
    "links": [
        {
            "url": null,
            "label": "« Previous",
            "active": false
        },
        {
            "url": "https://activitymessenger.com/api/v1/organization/1234/published_templates?page=1",
            "label": "1",
            "active": true
        },
        {
            "url": null,
            "label": "Next »",
            "active": false
        }
    ],
    "next_page_url": null,
    "path": "https://activitymessenger.com/api/v1/organization/1234/published_templates",
    "per_page": 10,
    "prev_page_url": null,
    "to": 1,
    "total": 1
}

The url attribute points to the message/template as a web page. The HTML is simple and contains no JavaScript and no external CSS files.

The background_color and background_images attributes define the background color outside of the template (usually dark gray), or an image.

The content_background_color attribute defines the content background color. The button_color defines the default button color. It could be overridden in each block.

The blocks attribute is a list of vertical blocks that compose the message/template. Blocks can be used to reconstruct the template with your own CSS styling and HTML markup. These are the blocks currently supported and the attributes they use:

  • hero: Hero image. Use attributes: image_url, image_alt.
  • one-column: Single column of text with an optional button. Use attributes: text, button_url, button_text, button_color, button_target (https (default) or mailto).
  • image-column: Two columns with an image left and text right with an optional button. Use attributes: image_url, image_alt, image_cta_url (URL to go to if user clicks on image), text, button_url, button_text, button_color, button_target (https (default) or mailto).
  • column-image: Two columns with text left with an optional button, and image right. Use attributes: image_url, image_alt, image_cta_url (URL to go to if user clicks on image), text, button_url, button_text, button_color, button_target (https (default) or mailto).
  • spacer: Horizontal spacer. Attribute meta contains CSS styles to create the spacer.
  • video: Hero video preview with a link to open the video in another browser tab. Use attributes: image_url (video preview image), image_alt, image_cta_url (URL to video).
  • video-column: Two columns with a video preview left and text right with an optional button. Use attributes: image_url (preview of the video), image_alt, image_cta_url (URL to video), text, button_url, button_text, button_color, button_target (https (default) or mailto).
  • two-columns: Two columns with text each with an optional image, and an optional button. For the left column use attributes: image_url, image_alt, image_cta_url (URL to go to if user clicks on image), text, button_url, button_text, button_color, button_target (https (default) or mailto). For the right column, use the ones post-fixed with 2.

# Users (staff)

Users in Activity Messenger are administrators and staff who have access to the back-office of your organization. Activity Messenger users are uniquely identified by an email address. A user can manage/access multiple organizations. You can invite users, modify their permissions and revoke their access. Read the help page User management and permissions to find out more.

A user object contains these attributes. The confirmed attribute will be true if the user has confirmed their email and completed their Activity Messenger user account setup.

{
  "id": 1234,
  "first_name": "Harry",
  "last_name": "Potter",
  "email": "harry@hogwartsrec.com",
  "mobile": "555-123-1234",
  "permission": "staff",
  "confirmed": true
}

# GET /api/v1/organization/{organization}/users

Retrieve all users who have access to or manage the organization.


# GET /api/v1/organization/{organization}/users/{user}

Retrieve a user by ID.


# POST /api/v1/organization/{organization}/users

Invite a user to manage/access the organization. The email address is the key and required. Attributes first_name and last_name are also required. Attribute mobile is optional. If provided must be formatted as 555-123-1234. Attribute permission determines their access level. Can be one of: staff, staff_no_messaging or guest. Refer to the help page User management and permissions for details.

If a user does not already exist with an account in Activity Messenger they will be created. They will receive an email to set up their account and gain access to your organization. The endpoint will return a 201 status code.

If the user already exists, they will be granted access to the your organization with the provided permission. If they already had access to your organization, their permission will be updated. The user attributes will not be modified. Inviting users with the owner or admin permission levels is not supported by the API. It is also not possible to change the permission level of owner or admin users. Contact us if you require any of those abilities.


# PUT /api/v1/organization/{organization}/users/{user}

Update the permission of a staff within the organization. Only the permission attribute should be passed and can be modified. Same constraints as the POST endpoint.


# DELETE /api/v1/organization/{organization}/users/{user}

Revoke the user access to the organization.


# Members (memberships)

Members in Activity Messenger are people who have a membership in your organization. A member is identified by their unique ID in the database but may have a different client-facing membership_no as presented on their membership card barcode. You may always use the membership_no to lookup - those are guaranteed to be unique.

A member has active_at and expired_at dates. The membership is active within that window, inclusively. When those dates are null, the membership is always active. A membership expires at the end of the expired_at day.

A membership also has a status. When null the member is active. When pending or suspended, the membership should be blocked.

A member object contains these attributes.

{
  "id": 1234,
  "membership_no": 1234,
  "name": "Harry Potter",
  "first_name": "Harry",
  "last_name": "Potter",
  "email": "harry@hogwartsrec.com",
  "mobile": "555-123-1234",
  "expired_at": "2023-05-19",
  "active_at": "2022-05-19",
  "status": null,
  "image_url": null,
}

# GET /api/v1/organization/{organization}/members

Retrieve members. See Pagination section for instructions on how to fetch all memberships. For example, to retrieve the maximum pass query string ?per_page=250.


# GET /api/v1/organization/{organization}/members/{member}

Retrieve a member by membership_no or by database ID.


# POST /api/v1/organization/{organization}/members/{member}/checkin

Call when the membership card is scanned. In the URL, {member} is the membership_no or the database ID. In the payload, attribute location_id is for future use and should be set to null. Attribute action should either be pass or fail. Set to fail when outside of the active_at and expired_at window. Set to fail when status is not null. Upon successful call, simply returns HTTP code 200 with the member in the payload.

{
  "location_id": 4567,
  "action": "pass",
}

# Forms

Forms in Activity Messenger allow you to capture information from your users. Forms can be waivers, surveys, payment forms or anything else you may need. Read the help page Forms, surveys and waivers to find out more.

A form object contains these attributes:

{
  "id": 12345,
  "name": "COVID-19 Daily Screening",
  "url": "https://activitymessenger.com/p/ABC1234",
  "short_url": "https://am.lol/p/ABC1234",
  "tags": []
}

# GET /api/v1/organization/{organization}/forms

Retrieve all forms in the organization. You may filter by passing a list of tags[] in the query string. Any class matching the passed tags will be returned.


# GET /api/v1/organization/{organization}/form_tags

Retrieve all tags defined and used on forms.


# GET /api/v1/organization/{organization}/forms/{form}

Retrieves a single form. A form contains a list of questions. For example:

{
    "id": 6460,
    "name": "Newsletter",
    "type": "subscribers",
    "subtype": null,
    "url": "http://activitymessenger.localhost/p/ABC1234",
    "short_url": "https://am.lol/q/ABC1234",
    "tags": [],
    "questions": [
        {
            "type": "account_owner",
            "slug": "account_owner",
            "label": "Subscribe to our newsletter",
            "required": true,
            "options": {
                "name": "required",
                "name_label": "First and last name",
                "email": "required",
                "mobile": "optional"
            }
        },
        {
            "type": "custom",
            "slug": "custom",
            "label": "What are your interests?",
            "required": false,
            "options": {
                "values": [
                    "Sports activities and training",
                    "Day camps",
                    "Quidditch",
                    "Potions",
                    "Gym"
                ]
            }
        }
    ]
}

# POST /api/v1/organization/{organization}/forms/{form}/submit

Submits a respondent programmatically to a form with a JSON payload. Follow the question schema returned by GET forms/{form}. Each question should use the slug. For example:

{
    "account_owner": {
        "first_name": "Harry",
        "last_name": "Potter",
        "email": "harry@hogwartsrec.com"
    },
    "custom": [
        "Quidditch",
        "Potions"
    ]
}

Currently we only support submitting to subscribers type forms. Emails that you submit through the API will get removed from the marketing and non-marketing unsubscribes list if they happened to be there. This ensures you will be able to send any type of email to them. Activity Messenger will not create duplicates. Instead, it will merge respondents looking at the email address.

When you pass a person and attribute name is required, you may pass either name or the pair first_name and last_name. Activity Messenger will build the complementary attributes on the fly.


# Classes and events

Classes and events in Activity Messenger are used to manage a roster of participants for camps, classes or activities. A class object looks like this:

{
    "id": 1234,
    "tags": [],
    "name": "Tumbling Class",
    "description": "<p>Gymnastics tumbling...<p>",
    "maximum_attendance": 20,
    "attendance_form_filter": {
        "id": null,
        "check_today": false,
        "check_only_nos": false,
        "limit_selection_to_form_ids": null
    },
    "price": "100.00",
    "user_ids": [],
    "forms": [
        {
            "id": 52262,
            "name": "Tumbling session",
            "purchase_rule": null,
            "maximum_attendance": 20,
            "price": null,
            "tags": [],
            "url": "https://activitymessenger.com/p/ABCD123"
        },
        {
            "id": 64415,
            "name": "Tumbling Drop-in",
            "purchase_rule": "multiple",
            "maximum_attendance": 5,
            "price": "10.00",
            "tags": [],
            "url": "https://activitymessenger.com/p/EFGH456"
        },
        {
            "id": 64415,
            "name": "Tumbling Tryout",
            "purchase_rule": "multiple",
            "maximum_attendance": 1,
            "price": "0.00",
            "tags": [],
            "url": "https://activitymessenger.com/p/IJKL789"
        },
    ],
    "location": {
        "name": "Centre Bell",
        "alias": "Ice",
        "address": "1909 Av. des Canadiens-de-Montréal, Montréal, QC H3B 2S2"
    }
}

The forms array contains registration forms available for participants to register to a class/event. Multiple registration forms are possible. Each form defines the registration rules to the class. In such a way, you can define separate registration forms for session vs drop-in rules. Or you can price them differently.

  • null: the participant will register to all dates of the class
  • single: the participant can only register to one date. Use this to limit to a single drop-in.
  • multiple: the participant can register to multiple dates. Use this to allow multiple drop-ins.

You may optionally pass location. This will create a new location (under E-Commerce, Ressources) or update an existing one by the same name. It will be assigned to the class.


# GET /api/v1/organization/{organization}/classes?tags[]={tag}&tags[]={tag}

Retrieve all classes sold by the organization. You may filter by passing a list of tags[] in the query string. Any class matching the passed tags will be returned.


# GET /api/v1/organization/{organization}/classes/{class}

Retrieve a class provided its ID.


# POST /api/v1/organization/{organization}/classes

Create a new class. Pass this payload. The name attribute is required. The description attribute is nullable. The tags attribute must be an array of 0 or more tags. Tags are case sensitive. Tags that do not exist will be created. The user_ids lists the users (staff) than can access the attendance list of this class. Staff can be managed from the admin portal. The attendance_form_filter object allows you to configure checking that a form was filled. Where id is a form ID as returned by the GET Forms API endpoint. The coach will be able to change the form to check against in the UI. You can set limit_selection_to_form_ids to limit to a specific set of forms. If omitted (null or []), all forms will be selectable.

{
  "name": "Tumbling 101",
  "description": "<p>Learn to tumble.</p>",
  "tags": [
    "Summer",
    "Gymnastics"
  ],
  "user_ids": [
    10210,
    34587,
  ],
  "attendance_form_filter": {
    "id": 1234,
    "check_today": false,
    "check_only_nos": false,
    "limit_selection_to_form_ids": [1234, 5678],
  }
}

# PUT /api/v1/organization/{organization}/classes/{class}

Updates a class given the {class} ID. The payload is the same as for create.


# DELETE /api/v1/organization/{organization}/classes/{class}

Archives a class give {class} ID. It will no longer be visible in the admin and staff portal. An admin can restore it from the admin portal.


# GET /api/v1/organization/{organization}/class_tags

Retrieve all tags defined and used on classes.


# Attendance

These endpoints allow you to create and update the class roster and class schedule. The payloads is a JSON representation of the CSV or Excel file formats we support.

Refer to the Attendance and the Excel/CSV import help pages for context and admin workflows.

Here is an example JSON payload of 4 participants attending a class on 4 dates. Not all participants are attending all dates.

[
  {
    "first_name": "Draco",
    "last_name": "Malfoy",
    "email": "luciusm@hogwartsrec.com",
    "mobile": "555-666-6666",
    "date_of_birth": "2008-06-05",
    "gender": "Male",
    "allergies": "Peanuts",
    "medical_conditions": "Asthma",
    "group_name": "Slytherin",
    "pickup_authorized": "Lucius Malfoy",
    "allow_sunscreen": "no",
    "allow_photo": "yes",
    "allow_leave": "yes",
    "daycare": "am pm",
    "pickup_password": "mischief",
    "friend": "",
    "custom": "Slytherin",
    "account_owner_first_name": "Lucius",
    "account_owner_last_name": "Malfoy",
    "account_owner_email": "luciusm@hogwartsrec.com",
    "account_owner_mobile": "555-666-6666",
    "other_guardian_first_name": "Narcissa",
    "other_guardian_last_name": "Malfoy",
    "other_guardian_email": "narcissam@hogwartsrec.com",
    "other_guardian_mobile": "555-666-6667",
    "event_dates": [
        "2021-10-18T19:00:00.000Z",
        "2021-10-19T19:00:00.000Z",
        "2021-10-20T19:00:00.000Z",
        "2021-10-21T19:00:00.000Z"
    ]
  },
  {
    "first_name": "Harry",
    "last_name": "Potter",
    "email": "lily@hogwartsrec.com",
    "mobile": "555-389-1284",
    "date_of_birth": "2008-07-31",
    "gender": "Male",
    "allergies": null,
    "medical_conditions": null,
    "group_name": "Gryffindor",
    "pickup_authorized": "Lily Potter",
    "allow_sunscreen": "no",
    "allow_photo": "yes",
    "allow_leave": "yes",
    "daycare": "am pm",
    "pickup_password": "bolt",
    "friend": "Ron",
    "custom": "Gryffindor",
    "account_owner_first_name": "Lily",
    "account_owner_last_name": "Potter",
    "account_owner_email": "lily@hogwartsrec.com",
    "account_owner_mobile": "555-389-1284",
    "other_guardian_first_name": "James",
    "other_guardian_last_name": "Potter",
    "other_guardian_email": "james@hogwartsrec.com",
    "other_guardian_mobile": "555-389-1293",
    "event_dates": [
        "2021-10-18T19:00:00.000Z",
        "2021-10-19T19:00:00.000Z",
        "2021-10-20T19:00:00.000Z"
    ]
  },
  {
    "first_name": "Ron",
    "last_name": "Weasly",
    "email": "arthur@hogwartsrec.com",
    "mobile": "555-123-1234",
    "date_of_birth": "2008-03-12",
    "gender": "Male",
    "allergies": null,
    "medical_conditions": null,
    "group_name": "Gryffindor",
    "pickup_authorized": "Arthur Weasly",
    "allow_sunscreen": "no",
    "allow_photo": "yes",
    "allow_leave": "yes",
    "daycare": "am pm",
    "pickup_password": "candy",
    "friend": "Harry",
    "custom": "Gryffindor",
    "account_owner_first_name": "Arthur",
    "account_owner_last_name": "Weasly",
    "account_owner_email": "arthur@hogwartsrec.com",
    "account_owner_mobile": "555-123-1234",
    "other_guardian_first_name": "Molly",
    "other_guardian_last_name": "Weasly",
    "other_guardian_email": "molly@hogwartsrec.com",
    "other_guardian_mobile": "555-456-1293",
    "event_dates": [
        "2021-10-18T19:00:00.000Z",
        "2021-10-19T19:00:00.000Z"
    ]
  },
  {
    "first_name": "Ginny",
    "last_name": "Weasly",
    "email": "arthur@hogwartsrec.com",
    "mobile": "555-123-1234",
    "date_of_birth": "2011-04-01",
    "gender": "Female",
    "allergies": null,
    "medical_conditions": null,
    "group_name": "Gryffindor",
    "pickup_authorized": "Arthur Weasly",
    "allow_sunscreen": "no",
    "allow_photo": "yes",
    "allow_leave": "yes",
    "daycare": "am pm",
    "pickup_password": "candy",
    "friend": "",
    "custom": "Gryffindor",
    "account_owner_first_name": "Arthur",
    "account_owner_last_name": "Weasly",
    "account_owner_email": "arthur@hogwartsrec.com",
    "account_owner_mobile": "555-123-1234",
    "other_guardian_first_name": "Molly",
    "other_guardian_last_name": "Weasly",
    "other_guardian_email": "molly@hogwartsrec.com",
    "other_guardian_mobile": "555-456-1293",
    "event_dates": [
        "2021-10-18T19:00:00.000Z",
        "2021-10-19T19:00:00.000Z",
        "2021-10-20T19:00:00.000Z",
        "2021-10-21T19:00:00.000Z"
    ]
  }
]

Each object represents a participant and the class dates they are attending. The only required attribute is the email address. All others are optional.

Attributes first_name, last_name, mobile, email define the participant. The email address is the key and is required.

Attribute gender is optional. If provided must be one of: Male, Female, NonBinary, NotSpecified or PreferNotToSay.

Attribute date_of_birth is optional. If provided must be formatted as YYYY-MM-DD. For example December 24th 2002 would be 2002-12-24.

Attributes daycare, pickup_password, friend and custom are optional fields you can use.

For child activities, you can set the primary parent using account_owner_* attributes.

You may have siblings or family members using the same email address. Please ensure the first_name is different.

You can set the second parent or emergency contact using the other_guardian_* attributes.

Attribute event_dates is an array of dates the participant is attending. Dates must be in ISO format. These dates also define the schedule of the class. If you leave empty the participant will not be attending any dates of the class.


# PUT /api/v1/organization/{organization}/classes/{class}/attendance

Creates or replaces the attendance list of a class. Will perform a smart merge using the email address as key and try to keep IDs intact. Will remove existing participants if not present in the payload.


# PATCH /api/v1/organization/{organization}/classes/{class}/attendance

Updates or appends to the attendance list of a class. Will merge participants using the email address as key. New participants can be added. You can remove a participant by providing the email address and first_name attributes and leave event_dates empty.


# GET /api/v1/organization/{organization}/classes/{class}/attendance

Retrieves the attendance list of a class. Returns an array of participants with their attendance schedule, check-in and check-out date/times. Attribute attendance contains an array of that data. This endpoint is NOT paginated.

  {
    "id": 2270673,
    "first_name": "Draco",
    "last_name": "Malfoy",
    "email": "luciusm@hogwartsrec.com",
    "mobile": "555-666-6666",
    "gender": "Male",
    "date_of_birth": "2008-06-05",
    "allergies": "Peanuts",
    "medical_conditions": "Asthma",
    "group_name": "Slytherin",
    "pickup_authorized": "Lucius Malfoy",
    "allow_sunscreen": "no",
    "allow_photo": "yes",
    "allow_leave": "yes",
    "daycare": "am pm",
    "pickup_password": "mischief",
    "friend": null,
    "custom": "Slytherin",
    "account_owner_first_name": "Lucius",
    "account_owner_last_name": "Malfoy",
    "account_owner_email": "luciusm@hogwartsrec.com",
    "account_owner_mobile": "555-666-6666",
    "other_guardian_first_name": "Narcissa",
    "other_guardian_last_name": "Malfoy",
    "other_guardian_email": "narcissam@hogwartsrec.com",
    "other_guardian_mobile": "555-666-6667",
    "event_dates": [
      "2021-10-18T19:00:00.000000Z",
      "2021-10-19T19:00:00.000000Z",
      "2021-10-20T19:00:00.000000Z",
      "2021-10-21T19:00:00.000000Z"
    ],
    "attendance": [
      {
        "start": "2021-10-18T19:00:00.000000Z",
        "in_at": "2021-10-18T19:04:25.000000Z",
        "out_at": "2021-10-18T20:34:12.000000Z"
      },
      {
        "start": "2021-10-19T19:00:00.000000Z",
        "in_at": null,
        "out_at": null
      },
      {
        "start": "2021-10-20T19:00:00.000000Z",
        "in_at": null,
        "out_at": null
      },
      {
        "start": "2021-10-21T19:00:00.000000Z",
        "in_at": null,
        "out_at": null
      }
    ]
  }
In addition to the event_dates attribute, the GET call also returns attribute attendance which holds check-in and check-out date/times.

# Building a class calendar


# GET /api/v1/organization/{organization}/class_events?start={YYYY-MM-DD}&end={YYYY-MM-DD}&tags[]={tag}&tags[]={tag}&category_id={category}

Retrieve all class events in a specific date range. Query string parameters start and end are mandatory. Dates are inclusive. You may filter by passing a list of tags[] in the query string. Any class matching the passed tags will be returned. You may also filter by passing a category_id. Both filters are optional. This endpoint is NOT paginated.


Using the GET class_events endpoint you can fetch all class events within a certain date range. The endpoint returns a list of events following the FullCalendar Event object format.

Each event is an occurrence of a class. This is a sample class event:

{
  "id": 1234,
  "start": "2021-08-31T19:00:00.000000Z",
  "end": "2021-08-31T20:00:00.000000Z",
  "title": "Tumbling",
  "borderColor": null,
  "extendedProps": {
    "type": "am_event",
    "am_class_id": 4567,
    "description": "<p>Open enrollment</p>",
    "maximum_attendance": 20,
    "number_of_spots": 18,
    "number_of_events": 10,
    "reserved": 2,
    "price": "120.00",
    "tax_info": {
      "display": 120,
      "after_tax": 131.97,
      "before_tax": 120,
      "inclusive_tax": 0,
      "exclusive_tax": 11.97,
      "tax": 11.97,
      "taxes": [
        11.97
      ],
      "names": [
        "TVQ 9.975%"
      ],
      "inclusive_names": [],
      "exclusive_names": [
        "TVQ 9.975%"
      ]
    },
    "tags": [
      "Summer",
      "Gymnastics"
    ],
    "forms": [
      {
        "id": 7890,
        "name": "Class payment form",
        "purchase_rule": "single",
        "maximum_attendance": 10,
        "number_of_spots": "8",
        "price": null,
        "tags": [],
        "url": "https://activitymessenger.com/p/BCND123",
        "iframe_url": "https://activitymessenger.com/p/i/BCND123"
      }
    ]
  }
}

The class has a default price and number of spots. However those can be overridden by the Payment form(s) used to sell the classes. The forms array contains those forms. You should have one button per form. Use the price and number of spots parameters in the form to display on your website. If they are null, fallback to the class ones.

You can sell a class by session or by drop-in. This is configured via the Class/Event question on the payment form itself. Possible values are: null to sell by session, single to sell a single drop-in at a time, and multiple to allow the customer to register to multiple drop-ins. The price parameter defines the selling price for the specified purchase_rule. For example to sell a session for 100$ set price to 100 and set purchase_rule to null. To sell a drop-in for 20$, set purchase_rule to single or multiple, and price to 20.

Classes can be grouped by category. Use the endpoint GET class_categories to retrieve a list. Classes can also be classified using tags. Use the endpoint GET class_tags to retrieve a list of tags. Endpoints to fetch classes and their events can be filtered using a list of tags, or by category.

Note: The tags[] query string to filter uses an OR operator. If you require an AND operator, you will need to process the result yourself.


# Bookings


# GET /api/v1/organization/{organization}/package_categories

Retrieve the package categories defined to group packages.


# GET /api/v1/organization/{organization}/package_categories/{package_category}/packages

Retrieve all packages contained in the package category.


# Products


# GET /api/v1/organization/{organization}/products?tags[]={tag}&tags[]={tag}

Retrieve all products sold by the organization, including hidden ones to the public. You may filter by passing a list of tags[] in the query string (optional). Any product matching the passed tags will be returned.


# GET /api/v1/organization/{organization}/product_tags

Retrieve all tags defined and used on products.