Sagenda API v3

Re-designed system interface for more productivity

Introduction

Sagenda’s new refined Application Programming Interface (API) provides clarity and expressiveness to interaction with our booking system for third-party developers.

You can follow a step-by-step guide laid out in this page for detailed info and then try it out using Mashape platform.

All requests to API v3 endpoints are to be performed via HTTPS. HTTP requests are redirected to HTTPS endpoint with HTTP 301 code

Authentication

For most API operations you will be required to provide an access token. Note that this is different from your Authentication Code in Account Settings, but you’ll still need one to obtain an actual token. Authentication code can be found in the Dashboard or in Settings / General Settings / Authentication code. Your authentication code looks like a 32 chars alphanumeric string.

Please, note: all path to API endpoints in this document are given relative to the website (sagenda.net) domain

Getting access token

Endpoint URL: /api/v3/token
Method: POST
Authentication required: No

Submit a POST request with the Content-Type: x-www-form-urlencoded header, with a body like this:

grant_type=api_token&api_token=[authentication-code]

You should substitute [authentication-code] with the code you’ve got from your Sagenda account settings.

Sample call (ajax)

$.ajax({
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/token",
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded"
  },
  "data": {
    "grant_type": "api_token",
    "api_token": "[authentication-code]"
  }
}).done(function (response) {
  console.log(response);
});

In case of a valid token, you’ll receive a JSON response with a following format:

{
  "access_token": "[access-token]",
  "token_type": "bearer",
  "expires_in": [expiration]
}

Where [access-token] is a string containing an access token, [expiration] is time in seconds before this token expires. We suggest that you store this information locally and request a new token only when this one expires. A token, once issued, is valid for all requests.

Using your access token

Endpoint URL: /api/v3/status/oauth
Method: GET
Authentication required: Yes

To authenticate using access token, you should supply it in the HTTP Authentication header, using the Bearer scheme. It looks like this:

Authentication: Bearer [access-token]

Please note that access token shouldn’t be wrapped in quotes, it’s just a string value you’ve got from authentication endpoint. Unsuccessful authentication attempts will result in HTTP 403 Forbidden response.

From now, for each endpoint that says “Authentication required: Yes” you’re required to include valid Authentication header within your request

To check you have an authentication working, you can submit a GET request with the authentication header as described above to this endpoint. HTTP 200 response means you’re all set to use API with this temporary token! Invalid token will return HTTP 403. Please note that this is just for your convenience while developing, you are not required to call this.

Sample call (ajax)

$.ajax({
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/status/oauth",
  "method": "GET",
  "headers": {
   "Authorization": "Bearer [access-token]"
  }
}).done(function (response) {
  console.log(response);
});

Getting bookable items

Endpoint URL: /api/v3/bookableItems
Method: GET
Authentication required: Yes

Make sure you have some bookable items defined in your Sagenda account, then call this endpoint to get a list of them in simple JSON array. Only identifier and name fields are guaranteed to be present in objects, other fields are optional and undefined by default.

Sample call (ajax)

$.ajax(
{
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/status/oauth",
  "method": "GET",
  "headers": {
    "Authorization": "Bearer [access-token]"
  }
}).done(function (response) {
  console.log(response);
});

Example response:

[
    {
        "identifier": "589261684dec5221a430bc28",
        "name": "Car",
        "location": "Mountainville, CA",
        "description": "Economy deal"
    },
    {
        "identifier": "5a00e9e54dec521ad8fd88a8",
        "name": "Boat"
    }
]

Where:
identifier: string (Item id)
name: string (Item name)
location: string, undefined (Optional. Item location field. If empty – undefined)
description: string, undefined (Optional. Item description field. If empty – undefined)

Fetching events for bookable item

Endpoint URL: /api/v3/events/[startDate]/[endDate]/[bookableItem]
Method: GET
Authentication required: Yes

Now that you have a list of bookable items, you can pick an identifier of one of them and request events from associated event schedules you’ve defined in your Sagenda account. This routine only returns events that are in future and available for booking.

Parameters are passed via URL:
startDate: string (An inclusive search start date in ISO 8601 format –  YYYY-MM-DD, e.g. 2018-03-24)
endDate: string (An inclusive search end date in ISO 8601 format –  YYYY-MM-DD)
bookableItem: string (Alphanumeric identifier of the requested bookable item)

Sample call (ajax)

$.ajax({
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/events/2018-04-01/2018-04-23/5a424886dc94451bb0242e0f",
  "method": "GET"
}).done(function (response) {
  console.log(response);
});

Let’s have a look at an example response and go through all the options presented:

[
  {
      "identifier": "NWE2ZWI3Y2ZkYzk0NDUyZjk4MmJmMzI3OzQvMjMvMjAxOCAxMjowMCBBTTs1YTQyNDg4NmRjOTQ0NTFiYjAyNDJlMGY=",
      "type": "allDay",
      "date": "2018-04-23",
      "endDate": "2018-04-25",
      "payment": {
          "amount": 14.88,
          "currencyCode": "USD",
          "note": "Pre-payment for reservation"
      },
      "membership": {
          "maximum": 3,
          "reserved": 1
      }
  },
  {
      "identifier": "NWFiZDkyM2JkYzk0NDUyZmY0N2UyY2E1OzQvMjMvMjAxOCA1OjAwIEFNOzVhNDI0ODg2ZGM5NDQ1MWJiMDI0MmUwZg==",
      "type": "schedule",
      "from": "2018-04-23T05:00Z",
      "to": "2018-04-23T07:00Z"
  },
  {
      "identifier": "NWFiZDkyM2JkYzk0NDUyZmY0N2UyY2E1OzQvMjMvMjAxOCA1OjAwIEFNOzVhNDI0ODg2ZGM5NDQ1MWJiMDI0MmUwZg==",
      "type": "dateAndTime",
      "from": "2018-04-23T12:00Z",
      "to": "2018-04-25T18:00Z"
  }
]

As you can see, there are many possibilities, so let’s break them down. Response from this endpoint is always a JSON array, containing zero or more events that belong to the requested time range.

Each object is guaranteed to have a unique identifier (you will need it later for booking), type (corresponds to your event schedule type), and some variables, depending on type:
for “allDay” type (All Day event):
date: string (Date of the event beginning in YYYY-MM-DD format)
endDate: string (Date of the event end in YYYY-MM-DD format)
for “schedule” or “dateAndTime” type (Schedule or Date and time event):
 from: string (Timestamp of the event beginning in YYYY-MM-DD’T’HH:MM’Z’ format – ISO 8601 w/o seconds)
to: string (Timestamp of the event end in YYYY-MM-DD’T’HH:MM’Z’ format – ISO 8601 w/o seconds)

Although time is denoted as being UTC (Z), it is actually user-defined time not belonging to a particular timezone (we don’t ask people to specify timezone for events). You should treat every timestamp as local time and do not perform any operations on it

Other variables are only present for certain types of events:
for paid events (with our PayPal module):
payment: object (Represents an info about payment for this particular occurrence)
amount: decimal (Actual amount to be paid)
currencyCode: string (Three-letter ISO code for currency, e.g. USD, CHF, CNY)
note: string (Optional. Note to the buyer concerning this payment)
for multi-user events:
membership: object (Represents an info about this event occupancy)
maximum: integer (Maximum amount of member allowed under this event)
reserved: integer (How many member have already booked this event and are actively booking right now)

Please note that all these fields are for display purpose and your convenience. You need only event identifiers to book an event.

Acquiring event lock

Endpoint URL: /api/v3/eventLocks
Method: POST
Authentication required: Yes

You’ve picked an event identifier from previous step and now you need to put a hold on it, to prevent other users from booking it until a provided expiration timestamp. You need to send a POST request with application/json body, that looks like this:

{
  "eventIdentifier": "[event-identifier]",
  "userIdentifier": "[user-identifier]", // Optional
  "participants": 1 // Optional
}

Where eventIdentifier is the identifier string you’ve picked from event search response, and participants is the number of places you want to book under one member (default is one). Participant requests larger than two are only valid for multiuser events (see membership object in previous step).

userIdentifier field is set only if you want to manage (cancel or book) your event locks in bulk. A new identifier will be assigned for you if you don’t specify in the event lock request. After that you can use this received identifier in subsequent request just in case you need to book or cancel them all at once.

Please note that setting user identifier does not extend the expiration time of your event lock. If you’re booking many events, be sure to keep track of the lock’s expiry time

Sample call (ajax)

$.ajax({
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/eventLocks",
  "method": "POST",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer [access-token]"
  },
  "processData": false,
  "data": "{\"eventIdentifier\": \"[event-identifier]\",\"participants\": 1}"
}).done(function (response) {
  console.log(response);
});

If your request was successful, you’ll receive a uniform response:

{
    "identifier": "15b59439d53142b9a463eddd",
    "eventIdentifier": "NWE0MjRiMThkYzk0NDUxYzk0NGI2ZTViO1R1ZSwgMjYgRGVjIDIwMTcgMDA6MDA6MDAgR01UOzVhNDI0ODU1ZGM5NDQ1MWJiMDI0MmUwYw==",
    "userIdentifier": "6fad1f1e-cf01-4c1b-9c5b-549d17916ece",
    "expires": "2017-12-26T21:27Z",
    "participants": 1
}

Let’s go through variables:
identifier: string (Event lock identifier to be supplied for final booking step)
eventIdentifier: string (Copy of eventIdentifier this lock represents. For reference)
userIdentifier: string (Unique user identifier. If the valid identifier was supplied to the endpoint, returns it. Else, generates a new one)
expires: string (Expiry date/time for this event lock in ISO 8601 combined date-time format (YYYY-MM-DD’T’HH’:’MM’Z’) string, e.g. 2018-03-09T19:28Z)

Booking an event

Endpoint URL: /api/v3/events
Method: POST
Authentication required: Yes

Finally, after all the hard work, we get to book an event. You’ll need your event and lock identifiers, plus some user date that you are to collect. Booking request is sent as a JSON body and looks like this:

{
  "eventIdentifier": "[event-identifier]",
  "lockIdentifier": "[event-lock-identifier]",
  "member": { 
    "email": "mary_smiths@example.com",
    "courtesy": "Mrs.",
    "firstName": "Mary",
    "lastName": "Smiths",
    "phoneNumber": "+15082749385",
    "description": "Can be late by about 15 minutes"
  }
}

Where eventIdentifier is event identifier from event search response (also available within lock object for your convenience), and lockIdentifier should be valid and non-exprired lock identifier for that event,

Good news is, all of the member object fields are optional. But if you want to personalize your customer experience and keep track of your business, hang on:
– email: string (Customer e-mail. Will be used to send a booking confirmation)
firstName, lastName: string, string (Customer names, if applicable)
phoneNumber: string (Customer phone number. If you’re using our SMS module and want customer to be notified of the event, you should provide a valid international phone number here (with + prefix))
description: string (A place for customer notes to be communicated to event organizer)

You can mix and match any of member variable in your request.

Sample call (ajax)

$.ajax({
  "async": true,
  "crossDomain": true,
  "url": "https://sagenda.net/api/v3/events",
  "method": "POST",
  "headers": {
    "Content-Type": "application/json"
  },
  "processData": false,
  "data": "{\"eventIdentifier\": \"[event-identifier]\", \"lockIdentifier\": \"[event-lock-identifier]\",\"member\": { \"email\": \"example@example.com\" }}"
}).done(function (response) {
  console.log(response);
});

The routine returns HTTP 201 Created, if booking was successful for free event, and HTTP 202 Accepted, if booking accepted for paid event processing. Response for paid event booking will look like this:

{ 
  "message": "Please finish event booking by paying via supplied URL", 
  "paymentUrl": "https://paypal.com/..." 
}

So if you get this response, you should redirect a user to complete a payment on payment gateway website located at paymentUrl. After successful payment, it will be automatically processed and confirmation will be sent to member’s email

Conclusion

This covers the basics of using new Sagenda API. We’re constantly improving it and adding new features, so don’t forget to check up this page every once in a while. Meanwhile, you might want to get your hands wet with our ready-made templates at Mashape!