Skip to content

Instantly share code, notes, and snippets.

@tylergaw
Last active April 29, 2016 19:56
Show Gist options
  • Save tylergaw/7adddb70e72ad05b6d165a6937b1f660 to your computer and use it in GitHub Desktop.
Save tylergaw/7adddb70e72ad05b6d165a6937b1f660 to your computer and use it in GitHub Desktop.

Groundwork.JS Usage Guide

Overview

Groundwork.js is a small library to assist developer when working with The Groundwork platform. It provides a consistent interface to our APIs and handles the intricacies of authentication for you.

Groundwork.js is specifically for use in the browser. You can load it directly from our CDN as a <script> tag or import it into your application via a UMD interface.

Examples

You can view examples of the library in action on our examples page.

Configure

API Keys

Before trying to configure groundwork.js you will need an API Key from the Admin application.

Select the Organization and click Manage from the top nav. Copy the API Key from the Initiative you would like to work with.

Tip: When developing you can use your test organization to prevent cluttering your data with test records.

Creating an instance

Include groundwork.js into your project so that you have access to the Groundwork class. You can create an instance of the class and pass your API Key to the constructor:

var gw = new Groundwork({
    apiKey: '<your api key here>'
});

You can also set your API Key on an existing instance:

var gw = new Groundwork();
gw.apiKey = '<your api key here>';

The instance can now make requests to the API. I you need to change the URL you're making calls to, you can set the apiUrl field:

var gw = new Groundwork({
    apiKey: '<your api key here>',
    apiUrl: '<URL>'
});

gw.apiUrl = '<URL>';

Authentication

Once a user has created a profile they can authenticate with the platform. This is necessary to complete actions like updating their profile, updating a subscription and more.

Authenticate with an email and password

groundwork.js will handle a successful response and store the correct tokens for future requests.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.auth.fetchUsingPassword(<email>, <password>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "accessToken": "1.an-access-token",
  "tokenType": "Bearer",
  "expiresIn": null,
  "gwid": "000000-0000-0000-..."
}

Supporters

Supporters are simple records meant to store information about a potential supporter for your organization. This can take the form of a traditional contact form (name, email, etc) or something more specialized like the answers to a survery or quiz.

Supporter records have a set of common fields, and then a tags field which can be used to store arbitraty JSON data.

Creating a supporter record does not require authentication.

Create a supporter record

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.supporters.create({<supporter object>})
    .then(successHandler)
    .catch(errorHandler));
Parameter Required Type Default Description
email string Email address
givenName string Given name
familyName string Family name
address1 string Address line one
address2 string Address line two
city string City
state string State
country string Country
phone string Phone number
postalCode string Postal code
source string Arbitrary string indicating submission source
tags JSON JSON blob with any and all additional information you want recorded about the supporter
Additional notes on parameters
  • tags is arbitrary JSON--you can use it to submit whatever additional data you feel is necessary to associate with a Supporter. As long as the data submitted is a valid JSON object, it will be stored as a serialized string of JSON.
  • The platform sends each supporter submitted a welcome email. If you want to control which email template they are sent, you must submit the email template name as a root level attribute of tags, named email_template. For instance, to send the spanish language version of the basic welcome mailing, you would specify "email_template":"signup_main-es"
  • The total serialized length of the tags object may not be longer than 8192 characters. Serialization to the database is done without any additional whitespace being added. If you submit an oversized tags object, the request will fail.
  • To avoid triggering a welcome email, you send "send_email": 0 in the tags.

Response

{
    "address1": "123 Elm Street",
    "address2": "Apartment 3",
    "city": "Great Barrington",
    "country": "United States",
    "createdDate": "2015-04-11T23:29:02.225389Z",
    "email": "[email protected]",
    "familyName": "Jacobson",
    "givenName": "Jacob",
    "ipAddress": "192.168.33.1",
    "modifiedDate": "2015-04-11T23:29:02.225422Z",
    "postalCode": "01230",
    "source": "unittest-suite219",
    "state": "MA",
    "submittingUrl": "http://thegroundwork.com/not-a-real-page.html",
    "tags": {
        "dictKey": {
            "dictDictKey": {
                "dictDictKey1": "dictDictVal1",
                "dictDictKey2": "dictDictVal2"
            },
            "dictListKey": [
                "dictListVal1",
                "dictListVal2"
            ],
            "dictScalarKey": "dictScalarVal"
        },
        "email_template":"signup_main",
        "listKey": [
            "listVal1",
            "listVal2"
        ],
        "scalarKey": "scalarVal",
        "utm_medium": "alpha",
        "utm_notwhitelisted": "bravo"
    },
    "userAgent": "Test Script post_to_local_bucket.sh",
    "uuid": "63361fda-0c4d-47d6-873e-be78bf01d831"
}

Profiles

Profiles are user accounts created within The Groundwork platform. They are used to authenticate with the platform and manage donations and subscriptions. Every profile is assigned a gwid (Groundwork ID) which acts as a unique identifier across the platform.

Create a new profile

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.profiles.create({<profile object>})
    .then(successHandler)
    .catch(errorHandler));

Profile fields

Parameter Required Description
email Unique email address
password See password requirements
givenName First name for account holder
familyName Last name for account holder
dateOfBirth Date
honorificPrefix
honorificSuffix
gender See gender choices
genderIdentity
partyIdentification See party choices
emoloyer
occupation
phoneNumber
address1 street address
address2 address continued
locality city
state
zipCode

Password Requirements

Password must:

  • be at least 8 characters long
  • be less than 100 characters long
  • contain an uppercase character
  • contain a lowercase character
  • contain a numeric character

Gender Choices

Gender must be a small integer

  • 0 for "Male"
  • 1 for "Female"
  • 2 for "Other"
  • 3 for "Choose not to identify"

Political Party Choices

Political Party Identification

Political Party must be a small integer

  • 0 for "Democratic"
  • 1 for "Republican"
  • 2 for "Independent"
  • 3 for "None/Other"

Response

{
    "profile":
        {
            "gwid": "10f78bf5-b1fd-46ed-98a2-5a5352499fb5",
            "email": "[email protected]",
            "isStaff": false,
            "isActive": true,
            "isConfirmed": true,
            "confirmedAt": null,
            "dateJoined": "2015-01-29T18:31:07.435110",
            "dateModified": "2015-01-29T18:31:08.638842",
            "dateOfBirth": null,
            "givenName": "First",
            "familyName": "Last",
            "honorificPrefix": "",
            "honorificSuffix": "",
            "gender": null,
            "genderIdentity": "",
            "partyIdentification": null,
            "employer": "",
            "occupation": "",
            "phoneNumber": "",
            "address1": "",
            "address2": "",
            "locality": "",
            "state": "",
            "zipCode": ""
        }
    }
}

Fetch a new profile

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.profiles.fetch(<gwid>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
    "profile":
        {
            "gwid": "10f78bf5-b1fd-46ed-98a2-5a5352499fb5",
            "email": "[email protected]",
            "isStaff": false,
            "isActive": true,
            "isConfirmed": true,
            "confirmedAt": null,
            "dateJoined": "2015-01-29T18:31:07.435110",
            "dateModified": "2015-01-29T18:31:08.638842",
            "dateOfBirth": null,
            "givenName": "First",
            "familyName": "Last",
            "honorificPrefix": "",
            "honorificSuffix": "",
            "gender": null,
            "genderIdentity": "",
            "partyIdentification": null,
            "employer": "",
            "occupation": "",
            "phoneNumber": "",
            "address1": "",
            "address2": "",
            "locality": "",
            "state": "",
            "zipCode": ""
        }
    }
}

Update an existing profile

You can update one or more fields within a specific profile by gwid. The profile object should contain only the fields you wish to update.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.profiles.update(<gwid>, {<profile object>})
    .then(successHandler)
    .catch(errorHandler));

Profile fields

Parameter Required Description
email Unique email address
givenName First name for account holder
familyName Last name for account holder
dateOfBirth Date
honorificPrefix
honorificSuffix
gender See gender choices
genderIdentity
partyIdentification See party choices
emoloyer
occupation
phoneNumber
address1 street address
address2 address continued
locality city
state
zipCode

Response

{
    "profile":
        {
            "gwid": "10f78bf5-b1fd-46ed-98a2-5a5352499fb5",
            "email": "[email protected]",
            "isStaff": false,
            "isActive": true,
            "isConfirmed": true,
            "confirmedAt": null,
            "dateJoined": "2015-01-29T18:31:07.435110",
            "dateModified": "2015-01-29T18:31:08.638842",
            "dateOfBirth": null,
            "givenName": "First",
            "familyName": "Last",
            "honorificPrefix": "",
            "honorificSuffix": "",
            "gender": null,
            "genderIdentity": "",
            "partyIdentification": null,
            "employer": "",
            "occupation": "",
            "phoneNumber": "",
            "address1": "",
            "address2": "",
            "locality": "",
            "state": "",
            "zipCode": ""
        }
    }
}

Request a password reset

The Groundwork platform uses a standard token-based password reset flow. When a token is requested for a specific email, a token is sent to that email address allowing the recipient to setup a new password for their account.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.profiles.requestResetToken(<email>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
    "passwordReset": true
}

Reset password with token

Once a user has received their token they can reset their password with the following request.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.profiles.resetPassword(<token>, <new password>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
    "profile":
        {
            "gwid": "10f78bf5-b1fd-46ed-98a2-5a5352499fb5",
            "email": "[email protected]",
            "isStaff": false,
            "isActive": true,
            "isConfirmed": true,
            "confirmedAt": "2015-01-30T18:31:07.435110",
            "dateJoined": "2015-01-29T18:31:07.435110",
            "dateModified": "2015-01-29T18:31:08.638842",
            "dateOfBirth": null,
            "givenName": "Grace",
            "familyName": "Hopper",
            "honorificPrefix": "Adm.",
            "honorificSuffix": "",
            "gender": null,
            "genderIdentity": "",
            "partyIdentification": null,
            "employer": "",
            "occupation": "Computer Scientist",
            "phoneNumber": "",
            "address1": "",
            "address2": "",
            "locality": "",
            "state": "",
            "zipCode": ""
        }
    }
}

Donations

A note about currencies

The amount of a donation is stored as an integer representing the value in cents. For example, to send a donation of USD $10.00 you would send in the amount as 1000, which is 10.00 * 100. The same would apply for other currencies that are divisible: EUR € 12.50 would be stored as 1250, or 12.50 * 100.

For currencies which are not divisible, such as Japanese Yen (JPY) you would send in the exact amount: JPY 1240¥ would be stored as 1240.

We provide helper methods to help you with these conversions:

removeCurrencyFormatting

gw.donations.removeCurrencyFormatting('$1,123.33'); // '1123.33'

toCents

Note: Do not use this on indivisble currencies like Japanese Yen.

gw.donations.toCents('$1,000'); // '100000'
gw.donations.toCents('$1,123.33'); // '112333'

toIndivisible

Note: Only use this on currencies which cannot be divided into smaller units, such as Japanese Yen.

gw.donations.toIndivisible('¥12,300'); // '12300'
gw.donations.toIndivisible('¥12,300.55'); // '12301'

formatCurrency

Correctly format an integer as a string using the ISO-4217 currency code.

gw.donations.formatCurrency('1230', 'JPY'); // '¥1,230'
gw.donations.formatCurrency('123055', 'USD'); // '$1,230.55'

Currency handling

The platform can accept donations in different currencies. In your request payloads there is an optional currency field which accepts a valid ISO-4217 currency code. This defaults to USD if not sent.

Create a new donation

Summary: You can create a Donation using groundwork.js. This request does not need to be authenticated. Once you've created an instance of groundwork.js with your apiKey you can pass a Donation object (using the fields below) to create.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.donations.create({<donation object>})
    .then(successHandler)
    .catch(errorHandler));

Donation fields

Parameter Required Type Description
address1 x string First line of the donor's billing street address
address2 string Second line of the donor's billing street address
agreeToTerms x boolean Boolean indicating the user agreed to the legal terms around donating
amount x integer Amount of the Donation in cents
ccCvc x string CVC for the credit card
ccExpMonth x integer Month of the credit card expiration date
ccExpYear x integer Year of the credit card expiration date
ccNum x string Credit card number as a string with no separators
city x string City of donor's billing address
country string Country of donor's billing address
currency string ISO-4217 country code for this donation, defaults to USD
email x string Donor's email address used for this donation
emailTemplate string Name of the email template used to generate the receipt email
employer x string Donor's employer
familyName x string Family name of the donor
givenName x string Given name of the donor
gwid string Groundwork ID of the user making the donation
occupation x string Donor's occupation
passport string Donor's passport ID
paymentMethod string If included, must be "card". If left out of the request, "card" is assumed.
phone x string Donor's phone number used for this donation
raiser string Raiser associated with this donation
source string Used for analytics
state x string State of donor's billing address
submittingUrl string URL of the submitting page
tags JSON JSON object containing tracking information
zip x string Zipcode of donor's billing address

Get a list of donations

Summary: When making the request, you must supply one (and only one) of the four filtering criteria (gwid, subscription, quickCard, or email).

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.donations.list({<options>})
    .then(successHandler)
    .catch(errorHandler));

Optional fields

Parameter Default Description
email None Filter donation objects by the email
gwid None Filter donation objects by the gwid
page 1 Indicate which page of results to return
perPage 10 Indicates how many items to include on a page. Maximum: 50
quickCard None Filter donation objects by the quickCard
subscription None Filter donation objects by the subscription

Response

{
    "meta": {
        "count": 2,
        "params": {
            "email": "[email protected]",
            "page": 1,
            "perPage": 2
        },
        "totalPages": 15
    },
    "donations": [
        {
            "address1": "123 Elm Street",
            "address2": "",
            "amount": 2500,
            "city": "Brooklyn",
            "country": "US",
            "created": 1440619945,
            "deleted": null,
            "email": "[email protected]",
            "employer": "Acme",
            "familyName": "Jameson",
            "givenName": "James",
            "gwid": "",
            "id": "2a73158b951f4176853dfcc4c8da8f",
            "occupation": "Coyote",
            "phone": "5555555555",
            "processor": "stripeinc",
            "processorPaymentData": {
                "cardId": "card_16eAFxIFYAvnMfeGytGFL",
                "chargeId": "ch_16eAFxIFYAvnMfeGFBJKF"
            },
            "quickCard": "",
            "raiser": null,
            "state": "NY",
            "subscription": "",
            "tags": {},
            "zip": "11210"
        },
        {
            "address1": "123 Elm Street",
            "address2": "",
            "amount": 100,
            "city": "Brooklyn",
            "country": "US",
            "created": 1440615542,
            "deleted": null,
            "email": "[email protected]",
            "employer": "Acme",
            "familyName": "Jameson",
            "givenName": "James",
            "gwid": "",
            "id": "878244c46def40b0b1de4553641fe7",
            "occupation": "Bricklayer",
            "phone": "5555555555",
            "processor": "stripeinc",
            "processorPaymentData": {
                "cardId": "card_16e96wIFYAvnMfeGUYtEKm",
                "chargeId": "ch_16e96wIFYAvnMfeGxeZ6HV"
            },
            "quickCard": "",
            "raiser": null,
            "state": "NY",
            "subscription": "",
            "tags": {},
            "zip": "11210"
        }
    ]
}

Fetch a donation

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.donations.fetch({<donation id>})
    .then(successHandler)
    .catch(errorHandler));

Response

{
    "address1": "123 Elm Street",
    "address2": "",
    "amount": 100,
    "city": "Brooklyn",
    "country": "US",
    "created": 1440615542,
    "currency": "USD",
    "deleted": null,
    "email": "[email protected]",
    "employer": "Acme",
    "familyName": "Jameson",
    "givenName": "James",
    "gwid": "",
    "id": "878244c46def40b0b1de4553641fe7",
    "occupation": "Bricklayer",
    "phone": "5555555555",
    "processor": "stripeinc",
    "processorPaymentData": {
        "cardId": "card_16e96wIFYAvnMfeGUYtEKm",
        "chargeId": "ch_16e96wIFYAvnMfeGxeZ6HV"
    },
    "quickCard": "",
    "raiser": null,
    "state": "NY",
    "subscription": "",
    "tags": {},
    "zip": "11210"
}

Subscriptions

Subscription objects allow users to create a recurring donation. Monthly and weekly donations are supported.Subscriptions are recurring payments.

Create a new subscription

Example

let gw = new Groundwork({
  apiKey: <API_KEY>
});

gw.subscriptions.create({<subscrioption object>})
    .then(successHandler)
    .catch(errorHandler));

Subscription fields:

Parameter Required Type Description
amount x integer Amount of the Subscription in cents
gwid string Id of the user who made the donation
givenName x string Given name of the donor
familyName x string Family name of the donor
address1 x string First line of the donor's billing street address
address2 string Second line of the donor's billing street address
city x string City of donor's billing address
state x string State of donor's billing address
zip x string Zipcode of donor's billing address
country string Country of donor's billing address
email x string Donor's email address used for this donation
phone x string Donor's phone number used for this donation
employer x string Donor's employer
occupation x string Donor's occupation
ccNum x string Credit card number as a string with no separators
ccExpMonth x integer Month of the credit card expiration date
ccExpYear x integer Year of the credit card expiration date
ccCvc x string CVC for the credit card
tags JSON JSON object containing tracking information
raiser string Raiser associated with this donation
agreeToTerms x boolean Boolean indicating the user agreed to the legal terms around donating
source string Used for analytics
submittingUrl string URL of the submitting page
interval string Interval at which a subscription will be charged. Defaults to "monthly". Valid values are "monthly" and "weekly".
emailTemplate string Name of the email template used to generate the receipt email

Response

{
    "subscription": {
        "address1": "123 Main St",
        "address2": "",
        "amount": 100,
        "cancelled": null,
        "ccExpMonth": 12,
        "ccExpYear": 2020,
        "ccNumLast4": "4242",
        "ccType": "Visa",
        "city": "New York City",
        "country": "US",
        "created": 1440719921,
        "currentPeriodEnd": 1443398322,
        "currentPeriodStart": 1440719922,
        "email": "[email protected]",
        "employer": "Acme",
        "familyName": "Jameson",
        "givenName": "James",
        "gwid": "abc123",
        "id": "c3f5904a4073482f92d7701dcd0211e6",
        "interval": "monthly",
        "occupation": "Designer",
        "phone": "2125555555",
        "processor": "stripeinc",
        "processorPaymentData": {
            "customer": "cus_6sKwBd2aWd5OQJ"
        },
        "raiser": null,
        "state": "NY",
        "tags": {},
        "zip": "11201"
    }
}

Get a list of subscriptions

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.subscriptions.list(<options>)
    .then(successHandler)
    .catch(errorHandler)

Options fields:

Parameter Default Description
gwid None Filter donation objects by the gwid. Required.
email None Filter donation objects by the email
page 1 Indicate which page of results to return
perPage 10 Indicates how many items to include on a page. Maximum: 50

Response:

{
    "meta": {
        "count": 1,
        "params": {
            "email": "[email protected]",
            "page": 1,
            "perPage": 10
        },
        "totalPages": 1
    },
    "subscriptions": [
        {
            "address1": "123 Elm Street",
            "address2": "",
            "amount": 66600,
            "cancelled": 1440702374,
            "ccExpMonth": 1,
            "ccExpYear": 2017,
            "ccNumLast4": "2222",
            "ccType": "Visa",
            "city": "Brooklyn",
            "country": null,
            "created": 1440019810,
            "currentPeriodEnd": 1442698211,
            "currentPeriodStart": 1440019811,
            "email": "[email protected]",
            "employer": "The Groundwork",
            "familyName": "Jameson",
            "givenName": "James",
            "gwid": "c07688ac-acec-4e6d-b492-e021adadb3dd",
            "id": "1c75cb72f6c84b7abf54129b5278c4fe",
            "interval": "monthly",
            "occupation": "Designer",
            "phone": "5555555555",
            "processor": "stripeinc",
            "processorPaymentData": {
                "customer": "cus_6pIj0rbRQIAEFE"
            },
            "raiser": null,
            "state": "NY",
            "tags": {},
            "zip": "11210"
        }
    ]
}

Fetch a subscription

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.subscriptions.fetch(<subscription id>)
    .then(successHandler)
    .catch(errorHandler)

Response

{
    "subscription": {
        "address1": "123 Main St",
        "address2": "",
        "amount": 100,
        "cancelled": null,
        "ccExpMonth": 12,
        "ccExpYear": 2020,
        "ccNumLast4": "4242",
        "ccType": "Visa",
        "city": "New York City",
        "country": "US",
        "created": 1440719921,
        "currentPeriodEnd": 1443398322,
        "currentPeriodStart": 1440719922,
        "email": "[email protected]",
        "employer": "Acme",
        "familyName": "Jameson",
        "givenName": "James",
        "gwid": "abc123",
        "id": "c3f5904a4073482f92d7701dcd0211e6",
        "interval": "monthly",
        "occupation": "Designer",
        "phone": "2125555555",
        "processor": "stripeinc",
        "processorPaymentData": {
            "customer": "cus_6sKwBd2aWd5OQJ"
        },
        "raiser": null,
        "state": "NY",
        "tags": {},
        "zip": "11201"
    }
}

Delete (cancel) a subscription

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.subscriptions.del(<subscription id>)
    .then(successHandler)
    .catch(errorHandler)

Response

Note the cancelled field:

{
    "subscription": {
        "address1": "123 Main St",
        "address2": "",
        "amount": 100,
        "cancelled": 1440721294,
        "ccExpMonth": 12,
        "ccExpYear": 2020,
        "ccNumLast4": "4242",
        "ccType": "Visa",
        "city": "New York City",
        "country": "US",
        "created": 1440719921,
        "currentPeriodEnd": 1443398322,
        "currentPeriodStart": 1440719922,
        "email": "[email protected]",
        "employer": "Acme",
        "familyName": "Jameson",
        "givenName": "James",
        "gwid": "",
        "id": "c3f5904a4073482f92d7701dcd0211e6",
        "interval": "monthly",
        "occupation": "Designer",
        "phone": "2125555555",
        "processor": "stripeinc",
        "processorPaymentData": {
            "customer": "cus_6sKwBd2aWd5JPZ"
        },
        "raiser": null,
        "state": "NY",
        "tags": {},
        "zip": "11201"
    }
}

Change the amount of a subscription

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.subscriptions.updateAmount(<subscription id>, <new amount>)
    .then(successHandler)
    .catch(errorHandler)

Response

{
    "subscription": {
        "address1": "123 Main St",
        "address2": "",
        "amount": 200,
        "cancelled": null,
        "ccExpMonth": 12,
        "ccExpYear": 2020,
        "ccNumLast4": "4242",
        "ccType": "Visa",
        "city": "New York City",
        "country": "US",
        "created": 1440719921,
        "currentPeriodEnd": 1443398322,
        "currentPeriodStart": 1440719922,
        "email": "[email protected]",
        "employer": "Acme",
        "familyName": "Jameson",
        "givenName": "James",
        "gwid": "",
        "id": "c3f5904a4073482f92d7701dcd0211e6",
        "interval": "monthly",
        "occupation": "Designer",
        "phone": "2125555555",
        "processor": "stripeinc",
        "processorPaymentData": {
            "customer": "cus_6sKwBd2aWd5JPZ"
        },
        "raiser": null,
        "state": "NY",
        "tags": {},
        "zip": "11201"
    }
}

Overview

A Groundwork Event is a representation of a real-word event occurring at a defined place during a defined time window, and is attended by a set of people who have obtained tickets to that Event. The Groundwork allows an organization to create and manage events, invitations, ticketing, ticket redemption and messaging for events created by organization administrators or by authenticated users affiliated with the organization.

Groundwork Events currently support a free ticket model. Paid tickets are envisioned for the near future.

Workflow

Below is a high-level description of the workflow supported by Events functionality.

Invitation and ticketing

An authenticated host or administrator creates an Event, then optionally sends Invitation emails via The Groundwork to that Event. Invitees may then accept or decline the Invitation. Each accepted Invitation corresponds to a Ticket, which references the attendee, the Invitation, and a Category. A Category describes a block of time within an Event, such as a shift.

Organizations may also direct individuals to a web page that presents Event details and allows them to obtain Tickets, regardless of whether they were invited or not.

An individual who obtains a Ticket is considered its purchaser. A purchaser may also obtain tickets on behalf of another person, a guest.

Ticket redemption

On the day of the Event, ticketholders "check in" and their Ticket is considered redeemed. Walk-up attendees can also obtain Tickets and redeem them at the Event.

Messaging

Invitation emails are currently the only message type supported, however other types such as attendance confirmation, cancellation and event followup messages with be supported soon.

Permissions

Events can be created by an organization's administrators or hosts. Event details can be viewed by anyone, without user authentication, but they may only be edited and deleted by the host that created them or by an administrator.

It is not necessary for invitees or attendees to authenticate to The Groundwork in order to receive Invitations or obtain Tickets, though the recommended flow is to authenticate users whenever possible.

Data model

  • An Event belongs to one Initiative.
  • An Event must have one host.
  • An Event must have at least one Category, each of which may have zero to many Tickets.
  • An Event may have zero to many Invitations, each of which must have one email address.
  • A Ticket is associated with one Category, one purchaser, and optionally any of: one attendee or one Invitation.

Events

An Event object is a time and a place of an event. It also encompasses an event's title and description.

List all Events

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.list({<options object>})
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
hostGwid GWID String of the user who is hosting the event. Only events with the given hostGwid will be returned
latitude Float of a latitudinal geographic coordinate by which to filter results. This parameter must be provided if performing a geographic filter
longitude Float of a longitudinal geographic coordinate by which to filter results. This parameter must be provided if performing a geographic filter
page Integer indicating which page of results should be returned
perPage Integer indicating how many results should be returned per request
radius Float, given in kilometers, of the search radius by with to filter results. This parameter must be provided if performing a geographic filter
startsBefore ISO-8601 formatted String given in local time without a timezone designator. Only events occurring before the given timestamp will be returned
startsAfter ISO-8601 formatted String given in local time without a timezone designator. Only events occurring after the given timestamp will be returned

Response

{
  "meta": {
    "count": 2,
    "params": {
      "page": 1,
      "perPage": 10
    },
    "total": 1,
    "totalPages": 1
  },
  "results": [
    {
      "address1": "641 Walnut St.",
      "address2": "",
      "addressCity": "Cincinnati",
      "addressCountry": "USA",
      "addressCounty": "",
      "addressDistrict": "",
      "addressLatitude": 39.103652,
      "addressLongitude": -84.512228,
      "addressPostalCode": "45202",
      "addressStateOrProvince": "Ohio",
      "description": "Come watch the Democratic and Republican nominees debate!",
      "hostGwid": "03d6b6c1-bf15-4401-a850-a0e6dd2be6de",
      "id": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
      "locationName": "The Righteous Room",
      "timeEndUtc": "2016-09-26T20:00:00Z",
      "timeStartUtc": "2016-09-26T17:00:00Z",
      "timeZoneId": "America/New_York",
      "title": "Debate Watch Party at The Righteous Room"
    }
  ]
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Create an Event

The provided address will be geocoded to discover timezone information. If the geocode fails, the request will fail and the Event will not be created.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.create({<event object>})
    .then(successHandler)
    .catch(errorHandler));

Event fields

Parameter Required Description
address1 String of the Address 1 line of the location of the Event. Max length: 128 characters
address2 String of the Address 2 line of the location of the Event. Max length: 128 characters
addressCity String of the City line of the location of the Event. Max length: 128 characters
addressCountry ISO-3166-1 Alpha-3 formatted String of the Country of the Event. Max length: 3 characters
addressCounty String of the County of the location of the Event. Max length: 128 characters.
addressDistrict String of the District of the location of the Event. Max length: 128 characters
addressPostalCode String of the Postal Code of the Event. Max length: 32 characters.
addressStateOrProvince String of the State of the Event. Max length: 128 characters
description String of the Event description
hostGwid GWID String of the user who is hosting the event. This field is only mandatory if the request is coming from an Admin. Otherwise, it defaults to the requesting user's GWID
locationName String name for the location. Max length: 256 characters
timeEnd ISO-8601 formatted String of the end time of the Event, given in local time, without a timezone designator
timeStart ISO-8601 formatted String of the start time of the Event, given in local time, without a timezone designator
title String with a maximum length of 256 characters.

Request

{
 "address1": "641 Walnut St.",
 "addressCity": "Cincinnati",
 "addressCountry": "USA",
 "addressPostalCode": "45202",
 "addressStateOrProvince": "Ohio",
 "description": "Come watch the Democratic and Republican candidates debate!",
 "locationName": "The Righteous Room",
 "timeEnd": "2016-09-26T15:00:00",
 "timeStart": "2016-09-26T12:00:00",
 "title": "Debate Watch Party at The Righteous Room"
}

Response

{
  "address1": "641 Walnut St.",
  "address2": "",
  "addressCity": "Cincinnati",
  "addressCountry": "USA",
  "addressCounty": "",
  "addressDistrict": "",
  "addressLatitude": 39.103652,
  "addressLongitude": -84.512228,
  "addressPostalCode": "45202",
  "addressStateOrProvince": "Ohio",
  "description": "Come watch the Democratic and Republican candidates debate!",
  "hostGwid": "03d6b6c1-bf15-4401-a850-a0e6dd2be6de",
  "id": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "locationName": "The Righteous Room",
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T17:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "Debate Watch Party at The Righteous Room"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Delete a specific Event, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.del(<event id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "status": 204,
  "statusText": "No Content"
}

Fetch a specific Event, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.fetch(<event id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "address1": "641 Walnut St.",
  "address2": "",
  "addressCity": "Cincinnati",
  "addressCountry": "USA",
  "addressCounty": "",
  "addressDistrict": "",
  "addressLatitude": 39.103652,
  "addressLongitude": -84.512228,
  "addressPostalCode": "45202",
  "addressStateOrProvince": "Ohio",
  "description": "Come watch the Democratic and Republican nominees debate!",
  "id": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "hostGwid": "03d6b6c1-bf15-4401-a850-a0e6dd2be6de",
  "locationName": "The Righteous Room",
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T17:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "Debate Watch Party at The Righteous Room"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Update an existing Event, by id

Note: only the fields that are passed will be updated.

If the address field is modified in full or in part, it will be re-geocoded to update timezone information. If the geocode fails, the request will fail and the Event will not be modified.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.update(<event id>, {<event object>})
    .then(successHandler)
    .catch(errorHandler));

Event fields

Parameter Required Description
address1 String of the Address 1 line of the location of the Event. Max length: 128 characters
address2 String of the Address 2 line of the location of the Event. Max length: 128 characters
addressCity String of the City line of the location of the Event. Max length: 128 characters
addressCountry ISO-3166-1 Alpha-3 formatted String of the Country of the Event. Max length: 3 characters
addressCounty String of the County of the location of the Event. Max length: 128 characters.
addressDistrict String of the District of the location of the Event. Max length: 128 characters
addressPostalCode String of the Postal Code of the Event. Max length: 32 characters.
addressStateOrProvince String of the State of the Event. Max length: 128 characters
description String of the Event description
hostGwid GWID String of the user who is hosting the event. This field is only mandatory if the request is coming from an Admin. Otherwise, it defaults to the requesting user's GWID
locationName String name for the location. Max length: 256 characters
timeEnd ISO-8601 formatted String of the end time of the Event, given in local time, without a timezone designator
timeStart ISO-8601 formatted String of the start time of the Event, given in local time, without a timezone designator
title String with a maximum length of 256 characters.

Request

{
  "description": "Come watch the Democratic and Republican nominees debate!"
}

Response

{
  "address1": "641 Walnut St.",
  "address2": "",
  "addressCity": "Cincinnati",
  "addressCountry": "USA",
  "addressCounty": "",
  "addressDistrict": "",
  "addressLatitude": 39.103652,
  "addressLongitude": -84.512228,
  "addressPostalCode": "45202",
  "addressStateOrProvince": "Ohio",
  "description": "Come watch the Democratic and Republican nominees debate!",
  "hostGwid": "03d6b6c1-bf15-4401-a850-a0e6dd2be6de",
  "id": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "locationName": "The Righteous Room",
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T17:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "Debate Watch Party at The Righteous Room"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Replace an existing Event, by id

Note: All fields are updated. If an optional field is not provided, it will be overwritten as blank unless otherwise noted.

If the address field is modified in full or in part, it will be re-geocoded to update timezone information. If the geocode fails, the request will fail and the Event will not be modified.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.replace(<event id>, {<event object>})
    .then(successHandler)
    .catch(errorHandler));

Event fields

Parameter Required Description
address1 String of the Address 1 line of the location of the Event. Max length: 128 characters
address2 String of the Address 2 line of the location of the Event. Max length: 128 characters
addressCity String of the City line of the location of the Event. Max length: 128 characters
addressCountry ISO-3166-1 Alpha-3 formatted String of the Country of the Event. Max length: 3 characters
addressCounty String of the County of the location of the Event. Max length: 128 characters.
addressDistrict String of the District of the location of the Event. Max length: 128 characters
addressPostalCode String of the Postal Code of the Event. Max length: 32 characters.
addressStateOrProvince String of the State of the Event. Max length: 128 characters
description String of the Event description
hostGwid GWID String of the user who is hosting the event. This field is only mandatory if the request is coming from an Admin. Otherwise, it defaults to the requesting user's GWID
locationName String name for the location. Max length: 256 characters
timeEnd ISO-8601 formatted String of the end time of the Event, given in local time, without a timezone designator
timeStart ISO-8601 formatted String of the start time of the Event, given in local time, without a timezone designator
title String with a maximum length of 256 characters.

Request

{
  "address1": "642 Walnut St.",
  "addressCity": "Cincinnati",
  "addressCountry": "USA",
  "addressPostalCode": "45202",
  "addressStateOrProvince": "Ohio",
  "description": "Come watch the Democratic and Republican candidates debate!",
  "locationName": "The Righteous Room",
  "timeEnd": "2016-09-26T15:00:00",
  "timeStart": "2016-09-26T12:00:00",
  "title": "Debate Watch Party at The Righteous Room"
}

Response

{
  "address1": "642 Walnut St.",
  "address2": "",
  "addressCity": "Cincinnati",
  "addressCountry": "USA",
  "addressCounty": "",
  "addressDistrict": "",
  "addressLatitude": 39.103652,
  "addressLongitude": -84.512228,
  "addressPostalCode": "45202",
  "addressStateOrProvince": "Ohio",
  "description": "Come watch the Democratic and Republican candidates debate!",
  "hostGwid": "03d6b6c1-bf15-4401-a850-a0e6dd2be6de",
  "id": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "locationName": "The Righteous Room",
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T17:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "Debate Watch Party at The Righteous Room"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Get a list of all Tickets across the system

When called by an authenticated user, it will return all Tickets that have that user as that purchaserGwid. When called by an Admin, it will return all tickets. Both responses are filterable with the optional query parameters.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.auth.fetchUsingPassword(<email>, <password>)

gw.events.listAllTickets({<options object>})
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
isRedeemed Boolean representing whether the ticket has been redeemed. Only tickets with the given redemption status will be returned
page Integer indicating which page of results should be returned
perPage Integer indicating how many results should be returned per request
purchaserGwid GWID String of the user who purchased the tickets. Only tickets with the given purchaser will be returned
startsBefore ISO-8601 formatted String given in local time without a timezone designator. Only tickets in categories occurring before the given timestamp will be returned
startsAfter ISO-8601 formatted String given in local time without a timezone designator. Only tickets in categories occurring after the given timestamp will be returned
purchaserGwid GWID String of the user who purchased the tickets. Only tickets with the given purchaser will be returned

Response

{
  "meta": {
    "count": 2,
    "params": {
      "page": 1,
      "perPage": 10
    },
    "total": 2,
    "totalPages": 1
  },
  "results": [
    {
      "attendeeGwid": "",
      "categoryId": "846d92e5-ffd3-43b5-84de-a3d5d7e250ac",
      "eventId": "cfdf4bfe-971a-46c9-9696-678a85e1dbfe",
      "id": "b4b0ee1c-95da-4e93-abfc-91d67093ad33",
      "invitationId": "",
      "purchaserGwid": "524a1efb-b390-476d-b5a4-a0867d8db916",
      "redeemedUtc": ""
    },
    {
      "attendeeGwid": "",
      "categoryId": "846d92e5-ffd3-43b5-84de-a3d5d7e250ac",
      "eventId": "cfdf4bfe-971a-46c9-9696-678a85e1dbfe",
      "id": "74e9976b-0e6b-4dfe-9e92-57b2267268f4",
      "invitationId": "",
      "purchaserGwid": "424a1efb-b390-476d-b5a4-a0867d8db916",
      "redeemedUtc": ""
    }
  ]
}

Unsubscribe an email address from all communication from a specific Event host

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.unsubscribe(<email>, <invitationId>)
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
email String email address that wishes to unsubscribe
invitationId UUID String unique identifier of the Invitation that triggered the unsubscribe request. This is used to map back to the sending host

Response

{
  "email": "[email protected]",
  "id": "187c0a41-0550-4832-a09e-302531093b56"
}

Event Category

A Category object is a sub-object of an Event. It describes a block of time within an Event, such as a shift.

List all Categories on an Event

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.listCategories(<event id>, {<options object>})
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
page Integer indicating which page of results should be returned
perPage Integer indicating how many results should be returned per request
startsBefore ISO-8601 formatted String given in local time without a timezone designator. Only events occurring before the given timestamp will be returned
startsAfter ISO-8601 formatted String given in local time without a timezone designator. Only events occurring after the given timestamp will be returned

Response

{
  "meta": {
    "count": 2,
    "params": {
      "page": 1,
      "perPage": 10
    },
    "total": 2,
    "totalPages": 1
  },
  "results": [
    {
      "description": "Reserved for our most active supporters",
      "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
      "id": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
      "quantityRemaining": 5,
      "quantityTotal": 10,
      "timeEndUtc": "2016-09-26T20:00:00Z",
      "timeStartUtc": "2016-09-26T18:00:00Z",
      "timeZoneId": "America/New_York",
      "title": "VIP"
    }
  ]
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Create a Category

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.createCategory(<event id>, {<category object>})
    .then(successHandler)
    .catch(errorHandler));

Category fields

Parameter Required Description
description String of the Category description
quantityTotal Integer of the total Tickets for the Category
timeEnd ISO-8601 formatted String of the end time of the Category, given in local time, without a timezone designator. The value passed must not be later than the end time of the Event
timeStart ISO-8601 formatted String of the start time of the Category, given in local time, without a timezone designator. The value passed must not be earlier than the end time of the Event
title String with a maximum length of 256 characters

Request

{
  "description": "Reserved for our most active supporters",
  "quantityTotal": 10,
  "timeEnd": "2016-09-26T15:00:00",
  "timeStart": "2016-09-26T13:00:00",
  "title": "VIP"
}

Response

{
  "description": "Reserved for our most active supporters",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "quantityRemaining": 10,
  "quantityTotal": 10,
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T18:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "VIP"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Delete a specific Category, by id

NOTE: If there are Ticket objects associated with that Category, the request will fail.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.delCategory(<event id>, <category id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "status": 204,
  "statusText": "No Content"
}

Fetch a specific Category, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.fetchCategory(<event id>, <category id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "description": "Reserved for our most active supporters",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "quantityRemaining": 5,
  "quantityTotal": 10,
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T18:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "VIP"
}

Update an existing Category, by id

Note: only the fields that are passed will be updated.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.updateCategory(<event id>, <category id>, {<category object>})
    .then(successHandler)
    .catch(errorHandler));

Category fields

Parameter Required Description
description String of the Category description
quantityTotal Integer of the total Tickets for the Category
timeEnd ISO-8601 formatted String of the end time of the Category, given in local time, without a timezone designator. The value passed must not be later than the end time of the Event
timeStart ISO-8601 formatted String of the start time of the Category, given in local time, without a timezone designator. The value passed must not be earlier than the end time of the Event
title String with a maximum length of 256 characters

Request

{
  "description": "Allocated for our most active supporters"
}

Response

{
  "description": "Allocated for our most active supporters",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "quantityRemaining": 5,
  "quantityTotal": 10,
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T18:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "VIP"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Replace an existing Category, by id

Note: All fields are updated. If an optional field is not provided, it will be overwritten as blank unless otherwise noted.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.replaceCategory(<event id>, <category id>, {<category object>})
    .then(successHandler)
    .catch(errorHandler));

Category fields

Parameter Required Description
description String of the Category description
quantityTotal Integer of the total Tickets for the Category
timeEnd ISO-8601 formatted String of the end time of the Category, given in local time, without a timezone designator. The value passed must not be later than the end time of the Event
timeStart ISO-8601 formatted String of the start time of the Category, given in local time, without a timezone designator. The value passed must not be earlier than the end time of the Event
title String with a maximum length of 256 characters

Request

{
  "description": "Reserved for our most active supporters",
  "quantityTotal": 10,
  "timeEnd": "2016-09-26T15:00:00",
  "timeStart": "2016-09-26T13:00:00",
  "title": "MVP"
}

Response

{
  "description": "Reserved for our most active supporters",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "quantityRemaining": 10,
  "quantityTotal": 10,
  "timeEndUtc": "2016-09-26T20:00:00Z",
  "timeStartUtc": "2016-09-26T18:00:00Z",
  "timeZoneId": "America/New_York",
  "title": "MVP"
}

NOTE: timeStartUtc and timeEndUtc is calculated at call-time and is derived from the discovered timeZoneId, based on address information, and the naive datetime timeStart / timeEnd provided upon creation.

Event Invitation

An invitation is an email correspondence used to inform people of an event.

List all invitations on an Event

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.listInvitations(<event id>, {<options object>})
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
page Integer indicating which page of results should be returned
perPage Integer indicating how many results should be returned per request
status String of the status by which you wish to filter. It may be accepted, declined, or pending

Response

{
  "meta": {
    "count": 2,
    "params": {
      "page": 1,
      "perPage": 10
    },
    "total": 2,
    "totalPages": 1
  },
  "results": [
    {
        "email": "[email protected]",
        "eventId": "3cd5fc23-b4e7-4469-aefe-e54493c7e123",
        "familyName": "Doe",
        "givenName": "John",
        "id": "dd380647-4630-4146-a5c9-7b533dbedf5e",
        "status": "pending"
    },
    {
        "email": "[email protected]",
        "eventId": "3cd5fc23-b4e7-4469-aefe-e54493c7e123",
        "familyName": "Smith",
        "givenName": "Jane",
        "id": "abc80647-4630-4146-a5c9-7b533dbedf5e",
        "status": "declined"
    }
  ]
}

Create a Invitation

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.createInvitation(<event id>, {<invitation object>})
    .then(successHandler)
    .catch(errorHandler));

Invitation fields

Parameter Required Description
email String of the email address of the Invitation recipient
familyName String of the family name (last name) of the Invitation recipient
givenName String of the given name (first name) of the Invitation recipient

Request

[
  {
    "email": "[email protected]",
    "familyName": "Doe",
    "givenName": "John"
  }
]

Response

[
  {
    "email": "[email protected]",
    "eventId": "3cd5fc23-b4e7-4469-aefe-e54493c7e123",
    "familyName": "Doe",
    "givenName": "John",
    "id": "dd380647-4630-4146-a5c9-7b533dbedf5e",
    "status": "pending"
  }
]

Delete a specific Invitation, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.delInvitation(<event id>, <invitation id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "status": 204,
  "statusText": "No Content"
}

Fetch a specific Invitation, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.fetchInvitation(<event id>, <invitation id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "email": "[email protected]",
  "eventId": "3cd5fc23-b4e7-4469-aefe-e54493c7e123",
  "familyName": "Doe",
  "givenName": "John",
  "id": "dd380647-4630-4146-a5c9-7b533dbedf5e",
  "status": "pending"
}

Update the status of an Invitation, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.updateInvitationStatus(<event id>, <invitation id>, <status>)
    .then(successHandler)
    .catch(errorHandler));

Invitation fields

Parameter Required Description
status String of the current RSVP status of the Invitation. It may be declined, or pending. You cannot accept an Invitation via this endpoint and method. To accept an invitation, you must create a ticket via gw.events.createTicket(). See Ticket Docs for more information. Note also that when status is updated from accepted to declined, the system deletes any tickets associated with that invitation id

Request

{
  "status": "declined"
}

Response

{
  "email": "[email protected]",
  "eventId": "3cd5fc23-b4e7-4469-aefe-e54493c7e123",
  "familyName": "Doe",
  "givenName": "John",
  "id": "dd380647-4630-4146-a5c9-7b533dbedf5e",
  "status": "declined"
}

Event Ticket

A Ticket object represents participation in a Category.

List all Tickets on a Category

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.listTickets(<event id>, <category id>, {<options object>})
    .then(successHandler)
    .catch(errorHandler));

Option fields

Parameter Required Description
isRedeemed Boolean representing whether the ticket has been redeemed. Only tickets with the given redemption status will be returned
page Integer indicating which page of results should be returned
perPage Integer indicating how many results should be returned per request
purchaserGwid GWID String of the user who purchased the tickets. Only tickets with the given purchaser will be returned

Response

{
  "meta": {
    "count": 2,
    "params": {
      "page": 1,
      "perPage": 10
    },
    "total": 2,
    "totalPages": 1
  },
  "results": [
    {
      "attendeeGwid": "752bfe79-fc8b-48e9-8f7f-67cdd1c7a67c",
      "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
      "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
      "id": "84e1e2c4-8ac9-4f38-9bd8-b1abfb8dc3d4",
      "invitationId": "",
      "purchaserGwid": "752bfe79-fc8b-48e9-8f7f-67cdd1c7a67c",
      "redeemedUtc": "2016-08-22T12:00:00Z"
    },
    {
      "attendeeGwid": "",
      "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
      "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
      "id": "36a91d28-dfaf-42c3-91ea-89806254ae35",
      "invitationId": "",
      "purchaserGwid": "f3fed15c-7007-4f39-82d8-930db0c3c0ea",
      "redeemedUtc": ""
    }
  ]
}

Create a Ticket

Notes When creating a ticket, you may choose one of four approaches to specify the attendee and/or purchaser:

  1. Set attendeeGwid and purchaserGwid to the same value. Choose this approach when the purchaser's Gwid is known, for example because the purchaser has authenticated to The Groundwork, and the purchaser is obtaining a ticket for themself.
  2. Set purchaserGwid and leave attendeeGwid empty. Choose this approach when when the purchaser's Gwid is known and the purchaser is obtaining a ticket for a guest with no known Gwid. Note that the attendeeGwid may be set later, for example when the guest registers at the door when attending an event.
  3. Set attendeeGwid and purchaserGwid to different values. Choose this approach when attendeeGwid and purchaserGwid are both known, but are different. This is most likely a rare case.
  4. Set email only. Choose this approach when the purchaser's Gwid is not known. The system will attempt to match the email sent to the email on existing profiles, then respond acccordingly:
    • If the email sent matches the email on an existing shadow profile (a shadow profile is a profile with no password set), the system will return the shadow profile's Gwid as both attendeeGwid and purchaserGwid.
    • If the email sent matches the email on an existing profile and the user has not authenticated, the system will return an HTTP 403
    • If the email sent does not match the email on any profiles, the system will create a new shadow profile and return its Gwid as both attendeeGwid and purchaserGwid

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.createTicket(<event id>, <category id>, {<ticket object>})
    .then(successHandler)
    .catch(errorHandler));

Ticket fields

Parameter Required Description
attendeeGwid String UUID of the person who will be attending the Event with this ticket. It may or may not be the same gwid as the purchaserGwid
email String email address of the person who will be purchasing this ticket. This must be passed if the purchaser's gwid is not known. It must not be passed otherwise
invitationId String UUID of the Invitation ID to associate with this ticket. If provided, the specified Invitation will update its status to accepted
purchaserGwid String UUID of the person who will be purchasing this ticket. It may or may not be the same gwid as the attendeeGwid. This is not necessary if the purchasing user is authenticated
redeemedUtc UTC ISO-8601 formatted String of the datetime at which the ticket was redeemed, formatted in UTC (any non-UTC datetimes will be converted to UTC)

Request

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "invitationId": "dd380647-4630-4146-a5c9-7b533dbedf5e"
}

Response

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "36a91d28-dfaf-42c3-91ea-89806254ae35",
  "invitationId": "dd380647-4630-4146-a5c9-7b533dbedf5e",
  "purchaserGwid": "f3fed15c-7007-4f39-82d8-930db0c3c0ea",
  "redeemedUtc": ""
}

Delete a specific Ticket, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.delTicket(<event id>, <category id>, <ticket id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "status": 204,
  "statusText": "No Content"
}

Fetch a specific Ticket, by id

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.fetchTicket(<event id>, <category id>, <ticket id>)
    .then(successHandler)
    .catch(errorHandler));

Response

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "36a91d28-dfaf-42c3-91ea-89806254ae35",
  "invitationId": "",
  "purchaserGwid": "f3fed15c-7007-4f39-82d8-930db0c3c0ea",
  "redeemedUtc": ""
}

Update an existing Ticket, by id

Note: only the fields that are passed will be updated.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.updateTicket(<event id>, <category id>, <ticket id>, {<ticket object>})
    .then(successHandler)
    .catch(errorHandler));

Ticket fields

Parameter Required Description
attendeeGwid String UUID of the person who will be attending the Event with this ticket. It may or may not be the same gwid as the purchaserGwid
invitationId String UUID of the Invitation ID to associate with this ticket. If provided, the specified Invitation will update its status to accepted
redeemedUtc UTC ISO-8601 formatted String of the datetime at which the ticket was redeemed, formatted in UTC (any non-UTC datetimes will be converted to UTC)

Request

{
  "redeemdUtc": "2016-08-22T12:00:00Z"
}

Response

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "36a91d28-dfaf-42c3-91ea-89806254ae35",
  "purchaserGwid": "f3fed15c-7007-4f39-82d8-930db0c3c0ea",
  "redeemedUtc": "2016-08-22T12:00:00Z"
}

Replace an existing Ticket, by id

Note: All fields are updated. If an optional field is not provided, it will be overwritten as blank unless otherwise noted.

Example

let gw = new Groundwork({
  apiKey: '<API_KEY>'
});

gw.events.replaceTicket(<event id>, <category id>, <ticket id>, {<ticket object>})
    .then(successHandler)
    .catch(errorHandler));

Ticket fields

Parameter Required Description
attendeeGwid String UUID of the person who will be attending the Event with this ticket. It may or may not be the same gwid as the purchaserGwid
invitationId String UUID of the Invitation ID to associate with this ticket. If provided, the specified Invitation will update its status to accepted
redeemedUtc UTC ISO-8601 formatted String of the datetime at which the ticket was redeemed, formatted in UTC (any non-UTC datetimes will be converted to UTC)

Request

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "redeemedUtc": "2016-08-22T13:00:00Z"
}

Response

{
  "attendeeGwid": "9465a252-3319-4471-a908-8e1333692bff",
  "categoryId": "d1365abf-5f70-4cb4-949e-a9f2222dcf84",
  "eventId": "5bc753e4-a94e-4463-a8e9-83de9c6819df",
  "id": "36a91d28-dfaf-42c3-91ea-89806254ae35",
  "purchaserGwid": "f3fed15c-7007-4f39-82d8-930db0c3c0ea",
  "redeemedUtc": "2016-08-22T13:00:00Z"
}

License

Copyright (c) 2016, The Groundwork / Timshel All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment