REST API¶
The REST API allows devices to access the data.
We use a short notation of the API endpoints in this documentation, to get the actual URI of a resource just prefix the
domain name and the /api
path like the examples below. This is a general rule that might change depending on the
project.
https://example.com/api/delegate
https://example.com/api/session/check-in
Request Format¶
The system understand requests sent in the following formats:
- JSON (preferred, default) when the
Content-Type
header of your request is set toapplication/json
; - XML when the
Content-Type
header of your request is set toapplication/xml
ortext/xml
; - Form Encoded when the header of your request is set to
application/x-www-form-urlencoded
; - Form Multipart when the header of your request is set to
multipart/form-data
.
Tip
Form Encoded and Form Multipart should be avoided if possible. This is mainly for their inexpressive and overcomplicated representation, good for web forms, bad for humans and debugging.
Take the following as an example, which representation do you find more readable and concise?
{
"delegate_id": 3,
"questionnaire_code": "ee86134a-7418-4cf9-8500-4a86353ffab7",
"answers": [
{ "question_id": 1, "answer_id": 1, "value": "Yes" },
{ "question_id": 2, "answer_id": 3, "value": "Pizza" },
{ "question_id": 3, "value": "I can write anything I want in here" }
]
}
delegate_id=1&
questionnaire_code=ee86134a-7418-4cf9-8500-4a86353ffab7&
answers%5Ba%5D%5Bquestion_id%5D=1&
answers%5Ba%5D%5Banswer_id%5D=1&
answers%5Ba%5D%5Bvalue%5D=Yes&
answers%5Bb%5D%5Bquestion_id%5D=2&
answers%5Bb%5D%5Banswer_id%5D=3&
answers%5Bb%5D%5Bvalue%5D=Pizza&
answers%5Bc%5D%5Bquestion_id%5D=3&
answers%5Bc%5D%5Bvalue%5D=I%20can%20write%20anything%20I%20want%20in%20here
Both examples have been formatted to improve readability, the actual request body should strip all unnecessary spaces
Response Format¶
You can pick the response format simply appending a dot .
and the format name of your choice, one in: json
,
(preferred, default) xml
.
GET /delegate/id:820
GET /delegate/id:820.json
GET /delegate/id:820.xml
The first two calls in the example above will return the very same response, JSON encoded.
Response Status Code¶
The response status code is possibly the most important bit of a response because it can tell you at a glance if what
you asked for has been processed correctly or not. All API methods will return an appropriate HTTP status code ranging
between 200
and 431
, but if something unforeseeable happens they might return an HTTP status code ranging
between 500
and 510
.
Error Responses¶
An error response will look like this:
{
"code": 404,
"message": "Not Found",
"errorCode": 0
}
- code
- This matches the HTTP status code.
- message
- Brief description of the error.
- errorCode
- Some API methods return a specific error code that uniquely identify a particular scenario. Some time an error code is guarantee to be returned if a determined set of circumstances does happen.
When the unexpected does happen…
While it’s always a good idea to parse the response looking for the data you’ve requested or for an error message,
when the status code is a 5xx
you might get back an HTML body or an empty body. This mainly happens when your call
does not even get to be processed because something unexpected happens before. As a rule of thumb you can try and parse
a 5xx
response body, but be prepared to fail gracefully if that fails.
Common 5xx
HTTP status codes are:
- 500 Internal Server Error
- 501 Not Implemented
- 502 Bad Gateway
- 503 Service Unavailable
- 504 Gateway Timeout
- 505 HTTP Version Not Supported
Tip
The best way of dealing with an unexpected error is to back off for a while and then try again. The back off timeout should be tuned depending on the method you are calling. If it’s vital that your call gets processed ASAP 500ms or 1s could be good choices, if your call is not high priority you can put it at the end of your queue for later processing or wait a few seconds before trying again.
Interaction Types¶
A non exhaustive list of the standard interactions is:
- check-in
- Indicates someone has checked in into a session or interacted with any device. It’s the most common action you can use anywhere you don’t need to define custom behaviour or attach complex data to it.
- check-out
- The opposite of a check-in, when someone leaves a session. Currently used to enable “single-entry” sessions.
- join
- Usually referred to a session, it’s a broad term and generally means that delegate is supposed to show up at a particular session or that they are allowed into such session.
- connect
- Indicates the intent of a delegate to connect with another delegate. Depending on the instance a single connect could trigger a connected event (see below) but usually for such event to trigger both delegates need to connect with each other first.
- connected [1]
- This is usually a system generated interaction that triggers when two delegates connect with each other.
- booking, cancel-booking
- These events allow you to book devices. The device you can book should be of a bookable type but this is not enforced. This has been used only for the meeting tables feature so far.
- invite, uninvite, notify-invitees
- These actions are used to invite delegates to a session and/or to notify them. This most likely requires some custom logic that can be added to the AppBundle.
- seen
- This is used only by UHF readers.
- entered, exited [1]
- This allow to detect how many delegates are in a particular area at an event.
Most interaction types we’ve used so far are summarised below:
Interaction | [2] | Description |
---|---|---|
check-in | R M S | A delegate shows up (physically) to an event or session |
check-out | M S | A delegate leaves an event or session |
join | R M S | A delegate is allowed to, has booked or is assigned to an event, session, … |
seen | U | A delegate has been seen at an event or session (usually by a UHF reader) |
entered | U | A delegate has entered an area (usually based on where they’ve been seen) |
exited | U | A delegate has left an area (usually based on where they’ve been seen) |
connect | S | A delegate sends a connection request |
connected | S | A delegate has connected with someone (usually when both reciprocally connect) |
booking | S | A delegate has booked something like a meeting, session, … |
cancel-booking | S | A delegate has cancelled a booking |
invite | S | A delegate has invited someone to something |
uninvite | S | A delegate has uninvited someone he previously invited |
notify-invitee | S | A delegate asks to notify an invitee about something |
order | M S | A delegate orders something, usually a drink |
order-processing | S | A delegate’s order is being processed |
order-cleared | S | A delegate’s order has been completed (usually this fires a text message) |
download | M S | A delegate requests to download something |
downloaded | M S | A delegate has downloaded something |
upload | M | A delegate uploads something |
feedback | S | A delegate sends their feedback |
competition | S | A delegate enters a competition |
voucher | S | A delegate consumes a voucher |
question | S | A delegate asks a question |
lead | M | A delegate records a lead |
poll-vote | S | A delegate votes in a poll |
own | M S | A delegate owns a device (usually for sponsors, to identify staff members) |
R | A delegate’s badge has been printed (usually from the registration app) |
[1] | (1, 2) You should never have to log such interaction, depending on the configuration for your particular instance of Satellite Tag the system will automatically log this events. |
[2] | R: Registration app, M: Mobile app, S: Mobi site/Exhibitor portal, U: UHF readers |
Barcode¶
A delegate barcode is generated according to a custom algorithm created to guarantee:
- uniqueness: if all the guidelines and conditions are met, codes might repeat after 5.6 years from the epoch start. This should give plenty of time since all our projects so far ran over a period of few hours to 6 months maximum.
- order: the generated codes are ordered based on the time they were generated with an accuracy of few milliseconds if all clocks on the clients are in sync, if they aren’t a few seconds of accuracy or more has to be expected.
- readability: codes related to the same group (or purchase in case of tickets) are easily identified because the share the same base (the first 12 characters of the barcode). Also, codes that belong to a sequence can be ordered or counted using the last two characters.
- strength: codes are protected by a check-sum that can detect (but not correct) tampering. The chances of generating a valid barcode without knowing the secret are negligible for our use cases.
- information rich: by analysing the barcode we can extrapolate meaningful data like:
- time of the barcode generation, with an error of ±3 minutes
- if it’s been generated by the server or a client
- which client generated it (if generated by a client)
- validity
- position in a sequence (if the barcode belongs to a group or sequence)
Barcode Parts¶
Each barcode can be seen as made of three components:
- base: the first 12 chars. The base doesn’t change within the same group or sequence or purchase;
- index: the last 3 chars, or 15 bits. They represent the position of this barcode in the sequence;
- check: the 3 chars between the base and the index, 15 bits. This is a check-sum that signs the “base + index” using a secret shared only among the server and clients.
The base is composed of (in order):
- days: 11 bits (2 chars + 1 bit)
- minutes: 9 bits (1 char and 4 bits)
- milliseconds: 15 bits (3 chars)
- use epoch: 1 bit
- random: 9 bits (1 char and 4 bits)
- server: 1 bit
- seed: 14 bits (2 chars and 4 bits)
See the below table for more details on the barcode parts.
Char | Bits | Part | Description |
---|---|---|---|
0 | 0-4 | Days | Number of days since the epoch. Because of the 10 bit size, this will repeat approximately every 5.6 years. |
1 | 5-9 | ||
2 | 10 | ||
11-14 | Minutes | Number of minutes today, 3 minutes approximation. | |
3 | 15-19 | ||
4 | 20-24 | Milliseconds | Number of milliseconds in the current 3 minutes frame, 5ms approximation. This helps keeping the barcodes ordered by creation time and allows generating 182 “ordered” barcodes per second. The number of barcodes that can be generated per second is actually much higher (in the order of 10¹⁸/s with the maximum number of clients generating barcodes simultaneously). |
5 | 25-29 | ||
6 | 30-34 | ||
7 | 35 | Use Epoch | This is 0 if the barcode has been generated without an epoch. The epoch is not stored in the barcode. |
36-39 | Random | This is a random number between 0 and 512. | |
8 | 40-44 | ||
9 | 45 | Server | This is 1 if the barcode has been generated on the server. |
46-49 | Seed | This is the seed that identifies the device that generated the barcode. | |
10 | 50-54 | ||
11 | 55-59 | ||
12 | 60-64 | Check | These are 15 check bits to prevent tampering or third party barcode generation. The system secret is required to generate a valid “check”. |
13 | 65-69 | ||
14 | 70-74 | ||
15 | 75-79 | Index | When grouping barcodes, for example tickets of the same purchase, this field allow to index them. This can index from 1 to 803. First 99 barcodes are suffixed with 00-99, after that the entire pool of character is used and the following indexes will look like: A0, A1, A2, … , Z9, ZA, ZB, … , ZX, ZY, ZZ. |
16 | 80-84 | ||
17 | 85-89 |
Barcode Generation¶
Using a common interface for the barcode generation across devices and programming language can help keeping the documentation consistent and improve the understanding of the internals.
The current API can be summarised as follows, using pseudo code:
/**
* Generate a new base for this client or server.
*
* @Parameter "seed" The client seed, must be unique per client
* @Parameter "epochStart" Unix timestamp of the midnight of the first day for the barcode generation, or -1 for a random epoch
* @Parameter "history" Previously generated bases, it's recommended that these are at least those generated in the past 3 minutes
* @Parameter "serverGenerated" Should be true only on the server
* @Return The array of bits for the base just generated
*/
function generateBase(int seed, int epochStart = -1, bit[][] history = [], bool serverGenerated = false): bit[]
/**
* Generate a new barcode for the given index and base, signed with the given secret.
*
* @Parameter "index" The position of this barcode in a sequence, or zero if the barcode doesn't belong to one
* @Parameter "secret" The shared secret to sign the barcode check-sum with
* @Parameter "base" The base to use for the barcode generation, or a random one if not provided
* @Return The array of bits for the barcode just generated
*/
function generateBarcode(int index = 0, string secret = '', bit[] base = []): bit[]
/**
* Generate a new barcode signed with the given secret.
*
* @Parameter "secret" The shared secret to sign the barcode check-sum with
* @Return The array of bits for the barcode just generated
*/
function generateSecure(string secret = '')
The reference implementation is in PHP, a JavaScript one will soon be implemented.