Skip to end of metadata
Go to start of metadata


The schedule stored in the Zermelo Portal is available as a set of appointments. Lessons, exams and other activities are all encoded as an appointment with a certain type. The endpoint you use to access this data is /appointments.

Note that the /appointments endpoint does actually return appointments versions. An unique appointment will be called an appointment instance from now on.

  • An appointment instance is the unique appointment. For example: a certain lesson maths in week 33, or a meeting with some teachers initially planned on april 2nd.
  • An appointment version is always linked to an appointment instance. An appointment instance always has a minimum of a single appointment version. When there is a change to the appointment a new appointment version will be created.

When the schedule is changed, for example when customizing a schedule for the day or for the week, for every changed appointment a new appointment version is created, and those are linked together through the appointmentInstance. The old appointment will have its valid field set to false. Comparing the original appointment with the new (modified) appointment will allow you to discover the differences between the two. For convenience the fields modifiedcancelledmoved and new are provided. A human readable description of the change is in changeDescription.

Retrieving and storing appointments is possible through the /appointments endpoint. See the Operations section for details on how to select a certain subset of the appointments etc. One of the most important selections is of course the time. If you want to specify an interval from which to return the appointments you can use the start and end parameters. You specify those as Unix timestamps and only appointments which start between those two instants will be returned.

Contents

Fields

For performance reasons some fields are currently not provided for by default. You can use the fields parameter to specify a list of fields you want to retrieve. To get all students for each appointment (and nothing else) do GET /api/v2/appointments?fields=id,students. Do not assume the following fields are the only ones you will receive. We may add additional fields as we need them. Note that the amount of fields returned by default may be reduced in new versions of the API.

Field

Type

Default

(v2)

First supported

Last supported

Description/Zermelo API implementation details

appointmentInstance

long

(tick)

API v2

Portal 1.1


The id of the appointment instance this appointment version belongs to. All appointment versions referring to the same appointment will refer to the same appointmentInstance. If an appointment repeats every week every occurrence will have a different appointmentInstance.

This field is generated when you upload an appointment version without specifying an appointment instance id. When you upload new versions of the same appointment be sure to specify the same appointmentInstance so the new version is linked to the correct appointment instance.

id

long

 (tick)API v1

The internal id of this version of the appointment. An appointment starts of with a single version. When it is modified new versions will be created and some fields of the existing versions may be modified.

For every appointment instance there will be 1 or more appointment versions returned by the /appointments endpoint. Those will all have a different id.

In v3 of the API appointment versions will never be deleted or disappear.

When does this appointment take place?

start

long

 (tick)API v1

UTC Unix time of the start of this appointment (the number of seconds elapsed since 1 January 1970). This is the first second this appointment is taking place.

end

long

 (tick)API v1

UTC Unix time of the end of this appointment (the number of seconds elapsed since 1 January 1970). This is the first second where this appointment is no longer taking place.

startTimeSlot

int

 (tick)

API v2

ZD 3.1


The numerical designation of the time slot during which this appointment starts. Usual values are between 1 and 9. This value is provided for convenience.

endTimeSlot

int

 (tick)API v2

The numerical designation of the time slot during which this appointment ends. Usual values are between 1 and 9. This value is provided for convenience.

adjustedTeachingTimelong
Not supported

NULL if the teaching time can be calculated using end - start.

If non-null, this is the teaching time that should be awarded to the students that are part of this appointment. This value is in seconds.

What is this appointment about?

subjects

list of strings

 (tick)API v2

The (human readable) subjects names or abbreviations this appointment is about.

subjectsDetailedlist of subject objects
Not supported
[{'id':2352, 'code':'ne',
'officialCode':'NETL', }, ...]

Note that not all subjects may have an officalCode.

type

string

 (tick)API v1

The type of this appointment. Valid values are "unknown", "lesson", "exam", "activity", "choice", "talk", "other"

remark

string

 (tick)API v1

Remark for this appointment. For example: "Don't forget your books".

Where does this appointment take place?

locations

list of strings

 (tick)API v1API v2

The names of the locations (classrooms) where this appointment will take place.

locationsOfBranchlist of locationOfBranch objects(tick)API v2
The identifiers of the locations (classrooms) where this appointment will take place.
Who is participating in this appointment?

teachers

list of strings

 (tick)API v1

The (three letter) codes/abbreviations of the teachers participating in this appointment.

teachersDetailed

list of employee objects


Not supported
[{'code':'aab',
'employeeNumber':'X234123b'}, ...]

Note that not all teachers may have an employee number.

students

list of strings


API v1

The students participating in this appointment. These are the student ids (Dutch: leerlingnummers/stamnummers) that are unique within the portal.

groups

list of strings

 (tick)API v1

The names of the student groups participating in this appointment. Usually most students will come from these groups. Note that this is a "human readable" list of groups and ID's may not be fully unique when there are multiple schools in the same portal.

groupsInDepartmentslist of groupInDepartment objects(tick)API v2
A list of the actual groups participating in this appointment. These ID's are unique and refer to actual group objects.

What is the status of the version of this appointment?

createdlong (tick)

API v2

Portal 1.1


The UTC Unix Time of when this appointment version was created. Useful to show a chronological view of the history of this appointment.
lastModifiedlong (tick)

API v2

Portal 1.1


Unix time (UTC) at which any fields of this version of the appointment were modified or when this version of the appointment was created. An update in the schedule will cause the previously valid appointment to be modified so it is no longer valid, and it will cause a new version of the appointment to be created with the modified properties. This field is used to receive incremental updates to the schedule using the modifiedSince query parameter.

valid

boolean

 (tick)API v1

True if this appointment is part of the most up-to-date schedule. Note that both valid and cancelled can be true, in which case the appointment has been cancelled and attendance is not required nor possible.

Only a single appointment(version) with the same appointmentInstance can have valid=true. Note that you may actually retrieve a set of appointment versions where there is not a single version with valid=true. That could happen when the appointment was moved to next week and you only requested this weeks appointments. It can also happen when you no longer have sufficient permissions to see the new version of the appointment.

If valid=false this version of the appointment is a past version that is no longer relevant. Users may still be interested in these (unless hidden=true). It is common to show these appointment versions as a "footprint" in the schedule so the user can see that there used to be an appointment here. The user may want to inspect this footprint to see where the appointment was moved to.

hiddenboolean (tick)

API v2

Portal 1.1


True if this version of the appointment was hidden and should not be shown to users. These appointment versions are not returned by default. Specify includeHidden=true to retrieve them.

You cannot have a version of an appointment with both hidden=true and valid=true. How would someone know he needs to attend?

baseboolean

API v2

Portal 1.1

No ZD support


If this is true, this appointment version is the first non-hidden one. Only a single version can have base=true. This can be interesting for statistics about the number of appointments that were cancelled.

cancelled

boolean

 (tick)API v1

True if this appointment has been cancelled. No attendance is required from anyone and the location is available for other appointments.

modified

boolean

 (tick)API v1

True if anything at all was changed in this version of the appointment. Only use this to show to a user, this field is not designed to be consumed by computers.

moved

boolean

 (tick)API v1

True if the start or end time or the location of this appointment were modified. Only use this to show to a user, this field is not designed to be consumed by computers.

new

boolean

 (tick)API v1

True if this appointment has been added and was not originally scheduled. Only use this to show to a user, this field is not designed to be consumed by computers.

changeDescription

string

 (tick)API v1

A textual description of the change to be shown to the user.

originalAppointment

id of appointment


API v2API v2

The original appointment; only used when either modified, moved or cancelled are true. This points to the previous version of the appointment. Deprecated, use the created field to order appointment versions.

updatedAppointment

id of appointment


API v2API v2

The appointment that replaces this one; only used when valid is false. This is a read-only field, the information is stored in originalAppointment. This points to the next version of the appointment. Deprecated, use the created field to order appointment versions.

Where does this appointment belong to?
branchOfSchoollong(tick)

API v2

Portal 1.2


Internal ID of the branch of the schoolInSchoolyear (Dutch: vestiging van school in schooljaar) this appointment belongs to. This may be NULL if this appointment does not belong to any branch.

If users can only see (data of) appointments of their own branch, this field determines if they can see the info of this appointment. This field is also used to determine which appointments someone modifying the daily schedule of a branch should concern himself with.

More information can be retrieved from the /branchesofschools endpoint.

branchstring (tick)API v1

Convenience field providing the branch code of the branchOfSchool. This is a string that has been chosen by the school and it can be used in the communication with other systems.

commonSchedulebool
Not supported

True if this appointment is part of the common schedule, e.g. if it was centrally scheduled. When a completely new schedule is published all these appointments may be removed or modified.

False if this was an appointment that was planned by someone else, for example by a teacher to meet with students. When a new schedule is published these appointments will be preserved. However, they may no longer be able to take place due to changing availabilities. Such an appointment might also be moved to another location if the previous location is no longer available.

Example

$ curl "https://xxxxxx.zportal.nl/api/v2/appointments?user=~me&start=1388998982&end=1389998982&access_token=xxxxxxxxxxxxxxxxxxx"
{
  "response": {
    "status":200,
    "message":"",
    "startRow":0,
    "endRow":27,
    "totalRows":27,
    "data":[
      {
        "id":51562,
        "appointmentInstance":21412,
        "start":42364236,
        "end":436234523,
        "startTimeSlot": 1,
        "endTimeSlot": 1,
        "subjects":["ne"],
        "teachers":["KRO"],
        "groups":["v1a"],
        "groupsInDepartments":[143],
        "locations":["M92"],
        "locationsOfBranch:[35],
        "type":"lesson",
        "remark":"Take care to bring your books",
        "valid":true,
        "cancelled":false,
        "modified":true,
        "moved":false,
        "new":false,
        "changeDescription":"The location has been changed from M13 to M92",
        ...
      },
      ...
    ]
  }
}

Compatibility matrix

IconDescription
(tick)Supported
(tick)(error)Supported but deprecated, will be removed in a future version
(error)Not supported
(info)Planned support < 6 months
(question)Proposal, no decision has been made if this will be supported
(star)Required on (initial) import

Field

Zermelo API

Zermelo

Desktop

itslearning


ExportsImportsExportsImports

appointmentInstance

(tick)

(tick)(tick)(question)

id

(tick)(error)(tick)(tick)
When does this appointment take place?

start

(tick)(tick)(star)(tick)(tick)

end

(tick)(tick)(star)(tick)(tick)

startTimeSlot

(tick)

(tick)(tick)(error)

endTimeSlot

(tick)

(tick)(tick)(error)
adjustedTeachingTime(question)(question)(question)
What is this appointment about?

subjects

(tick)(tick)(tick)(tick)
subjectsDetailed(question)(question)(question)

type

(tick)(tick)(tick)(tick)

remark

(tick)(tick)(tick)(tick)
Where does this appointment take place?

locations

(tick)(tick)(tick)(tick)
Who is participating in this appointment?

teachers

(tick)(tick)(tick)(tick)
teachersDetailed(question)(error)(question)

students

(tick)(tick)(tick)(tick)

groups

(tick)(tick)(tick)(tick)

What is the status of the version of this appointment?

created

(tick)

(tick)(tick)
lastModified

(tick)

(tick)(tick)

valid

(tick)(tick)(tick)(tick)
hidden

(tick)

(tick)(tick)
base

(question)

(question)(question)

cancelled

(tick)(tick)(tick)(tick)

modified

(tick)(tick)(tick)(tick)

moved

(tick)(tick)(tick)(tick)

new

(tick)(tick)(tick)(tick)

changeDescription

(tick)(tick)(tick)(tick)

originalAppointment

(tick)(error)(tick)(error)(tick)(error)(tick)

updatedAppointment

(tick)(error)(error)(error)(error)
Where does this appointment belong to?
branchOfSchool(question)(question)(question)(error)
branch(tick)(tick)(error)(tick)(error)
commonSchedule(question)(question)(question)(error)

Actions & GET parameters

The following are some examples on how to use the API:

ActionGET parameters
I'm a person and I want to know where I need to go. I'm not interested in cancelled appointments?valid=true&cancelled=false
I'm a person and I want to know where I need to go. I'm also interested in knowing if any appointments were cancelled.?valid=true
I'm a person and I want to see all appointments and their history. I'm not interested in changes that were hidden by the scheduler.?
I'm a computer system that needs the full history of all appointments, including old appointment versions that may never have made sense.?includeHidden=true
I'm a computer system and I only require changes that were made to the schedule so I can keep my own data in sync.

?modifiedSince=324324

&includeHidden=true

I'm a computer system and I only require changes to the schedule. I'm not concerned with appointment versions that were hidden. Using the API this way is not recommended!

?modifiedSince=324324

I'm a broken computer system that only needs changes in a schedule, without information about appointments that were hidden instead of cancelled. If you use this method you may end up with appointments in your calendar that should not be there. Using the API this way is not recommended!?modifiedSince=324324&valid=true

Synchronizing appointments with your own system

To facilitate the synchronization of appointments with another system the API includes the modifiedSince and includeHidden parameters.

ParameterDescriptionExample
modifiedSinceOnly return appointment versions that were modified since the indicated time(stamp). Note that there is a small delay (~30s) before changes become visible through this API call, and you may temporarily see a inconsistent state of the appointments. See Worst case scenario - race conditions below for details.GET /api/v3/appointments?modifiedSince=12432641
includeHiddenIn order to facilitate communication with other systems obsolete appointment versions will never just disappear. They will just be marked as "hidden". If you set this parameter to "true" the API will also return appointment versions that are hidden and should no longer be shown to users.GET /api/v3/appointments?includeHidden=true

The modifiedSince query parameter

appointmentModifiedSince

In the 19.02 release we added support for the appointmentModifiedSince parameter. This behaves exactly the same as modifiedSince, but does not include changes in student participation. This is useful if you only need to synchronize the schedule of teachers.

If another system needs to update their schedule they could of course remove all their internal state and replace it with a newly retrieved schedule. This is of course not optimal when there are a lot of appointment versions and only a small fraction has changed. It also does not work well when you store extra state (for example: homework). If you specify the modifiedSince parameter you will only get appointment versions that have been modified at a time later than the one you specify. If you use the modifiedSince parameter there will be a small delay in the changes that you will receive in order to guarantee the system has fully caught up.This delay is in the order of 30 seconds. The request will complete in the normal time but the newest appointment versions may be missing. The system needs this delay to become consistent and without this delay you could miss changes that are being done at the exact same time you are performing your request. It is very important that you use as modifiedSince the highest lastModified value you have received in your previous request. If you just use your own time you will miss updates. This is mainly due to the delay, as there will be a gap between the changes you received last time and the ones you will receive at your next request. Using lastModified this way will also guard you from problems when the clock of your server is off.

When using modifiedSince you should also use the parameter includeHidden=true.

Compare to HTTP

modifiedSince and lastModified actually behave the same as the HTTP headers If-Modified-Since and Last-Modified with some minor differences. Instead of 304 when there are no changes you will get a HTTP 200 response with no appointment versions, and instead of a HTTP 200 with the full (modified) content you will receive a HTTP 200 and only the modified appointment versions.

The life of an appointment

This describes the (fictional) story of an appointment. Note that (tick) is true and (error) is false.

First, an appointment is created (at 8:00):

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(tick)(error)(error)8:008:00

A new appointment instance is created when we POST a new appointment version. The id of this appointment instance is 234127. The appointment version also receives an id.

Then at 9:00, this appointment is moved to another timeslot:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(error)(error)(error)8:009:00
2341271002The moved version(error)(tick)(error)(error)9:009:00

Note that the appointment with id:1001 also has its lastModified field updated.

Current situation

This system is not fully implemented in Zermelo Desktop. As of nightly build 5-5-2015 all existing versions will be marked as hidden and two new versions wil be published. This will cause duplication of appointment versions. You should be able to process this using your normal logic.

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(error)(error)(error)(tick)8:009:00
2341271002The initially created version #2(tick)(error)(error)(error)8:009:00
2341271003The moved version(error)(tick)(error)(error)9:009:00


At 10:00 the appointment is cancelled:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(error)(error)(error)8:009:00
2341271002The moved version(error)(error)(error)(error)9:0010:00
2341271003The cancelled version(error)(tick)(tick)(error)10:0010:00


Now at 11:00, the scheduler notices it becomes a bit of a mess. He decides to discard the fact that the appointment was moved before being cancelled so the people won't see that change in their schedule:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(error)(error)(error)8:009:00
2341271002The moved version(error)(error)(error)(tick)9:0011:00
2341271003The cancelled version(error)(tick)(tick)(error)10:0010:00

Retrieving changes

We're using the changes as in Appointment version lifecycle example.

At 8:30 we perform the following request: GET /api/v3/appointments?modifiedSince=<7:30>&includeHidden=true The following appointment versions are returned:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(tick)(error)(error)8:008:00

We can't be sure we got all appointments until the current time. Changes do incur a delay of about 10 seconds before they will be returned. We note the time of 8:00 as the latest modification time of all returned appointments. This is important, if you just use the last time you checked you will miss updates!

Now, at 9:30 we do GET /api/v3/appointments?modifiedSince=<8:00>&includeHidden=true

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(error)(error)(error)8:009:00
2341271002The moved version(error)(tick)(error)(error)9:009:00

We do the same at 10:30: GET /api/v3/appointments?modifiedSince=<9:00>&includeHidden=true

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271002The moved version(error)(error)(error)(error)9:0010:00
2341271003The cancelled version(error)(tick)(tick)(error)10:0010:00

Note that now the appointment version with id 1001 is not included, as nothing about it was changed.

We repeat this at 11:30: GET /api/v3/appointments?modifiedSince=<10:00>&includeHidden=true

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271002The moved version(error)(error)(error)(tick)9:0011:00

You can see that we now only received the notification that the appointmentversion with id:2 was hidden. Other appointment versions remain unchanged.

Worst case scenario - race conditions

A special case to investigate is when changes are requested when they are in the process of being made. It should not be possible to get changes twice, zero times or incomplete changes. What would happen if we were to ask for changes at the exact time during which they are made? The following is a worst case scenario where a low frequency of modifiedSince requests happens to fall exactly on times where the schedule is updated.

First, an appointment is created (at 8:00), we do GET /api/v3/appointments?modifiedSince=<7:30>&includeHidden=true at the same time:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
No results!

We receive no results because the change of 8:00 will only be visible a few seconds later.

Then at 9:00, this appointment is moved to another timeslot, we do GET /api/v3/appointments?modifiedSince=<7:30>&includeHidden=true at the same time. Note that the modifiedSince parameter is still the same as we did not receive any changes the previous time:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
No results!

As the lastModified fields of both version with id:1001 and id:1002 were updated these are not returned. The last change has effectively hidden the previous one. If your update frequency is high enough this won't be a problem. Alternatively, you can retry a request without results a few minutes later if it is important to be no more than 1 hour out of date.

At 10:00 the appointment is cancelled, we do GET /api/v3/appointments?modifiedSince=<7:30>&includeHidden=true at the same time. Note that the modifiedSince parameter is still unchanged as we have not received any changes yet. Now we finally get some results:

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271001The initially created version(tick)(error)(error)(error)8:009:00

We are having some fairly bad luck. The only thing we know is that there was an appointment at this time in a previous version of the schedule, but we have not yet received or seen a valid one. Retrying a few minutes later would solve this of course. The only thing we can do in this case is create a footprint in our own database. The event itself does not yet have a valid state or time. Note that this case may also happen when an appointment is moved outside of the criteria we request appointments for.

Now at 11:00, the scheduler notices it becomes a bit of a mess. He decides to discard the fact that the appointment was moved before being cancelled so the people won't see that change in their schedule. We do GET /api/v3/appointments?modifiedSince=<9:00>&includeHidden=true Note that we updated the modifiedSince parameter this time as we did get results.

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271003The cancelled version(error)(tick)(tick)(error)10:0010:00

You can see that we confusingly enough do not yet see the id:1002 version, as it was just modified as we were requesting it. We have received a valid appointment now.

At 12:00 we do a final GET /api/v3/appointments?modifiedSince=<11:00>&includeHidden=true

appointmentInstanceidDescriptionbasevalidcancelledhiddencreatedlastModified
2341271002The moved version(error)(error)(error)(tick)9:0011:00

Now we receive the hidden id:1002 appointment, actually 2 hours after it was first created and 1 hour after it was hidden. We don't need to show this to the user.

  • No labels