Communication Format
Note
This page is only relevant when building new API clients. We provide client libraries for Java, C#, PHP, Python, and Ruby with the below already implemented.
SCORM Cloud’s v1 API is an imperative-style web API. (It is not RESTful.) It has a specific communication format for all API calls.
An API call is a GET or POST to a specific URL. All authenticated web service URLs are of the form:
https://cloud.scorm.com/api
?method=...
&appid=...
&ts=...
&sig=...
...any other parameters...
(without the newlines), where the parameters are:
method
the API method in question; for example, rustici.registration.createRegistration
appid
the application ID in which to operate
ts
the current time -- a UTC timestamp of the form yyyyMMddHHmmss. the current time in this format as recorded by SCORM Cloud’s servers can be viewed here
sig
the MD5 “signature” of the API method (defined below)
Unauthenticated API calls are not typically used by customers, but do exist; for example, the above current time link is the rustici.debug.getTime API call:
https://cloud.scorm.com/api?method=rustici.debug.getTime
As above, for regular customers, effectively all API calls are
authenticated, and so therefore will need the ts
and
sig
parameters. Since those parameters are ignored on
unauthenticated calls -- they don’t produce an error -- there’s
little reason to have special behavior for them in a library.
ts
parameter
The POST or GET to the API URL must be made within 15 minutes of the
ts
parameter’s value. Otherwise, the API will return the
error:
Timestamp sent is outside of expiration limit. Likely cause:
requesting server clock has drifted. Please sync requesting server
time to NTP time.
This error means that the current time (as it is on the SCORM Cloud
servers, which are synced to the AWS NTP time servers) is more than 15
minutes away from the ts
parameter sent in the URL. There
are two primary causes:
- the API call was made more than 15 minutes after the URL was generated (e.g., embedded in a web-page that a user idled on and then clicked later), or
- the time on the requesting server is wildly incorrect (which is not often the case)
To re-iterate: API call URLs are only valid for approximately 15 minutes once generated.
sig
parameter
The sig
parameter is defined as:
MD5( secretKey + parameterString )
where secretKey
is one of the secret keys for the
application ID included in the parameter list. The
parameterString
is the UTF8-encoded sorted, concatenated
list of key, value pairs for each parameter in the URL. For example, if
we wanted to make the API call rustici.registration.exists
for the registration with ID 1234
in the application with
ID APP123
, we’d have the following parameters:
regid: 1234
appid: APP123
method: rustici.registration.exists
ts: 20171024213655
Sort these values case-insensitively:
appid: APP123
method: rustici.registration.exists
regid: 1234
ts: 20171024213655
then concatenate them as key-value pairs with no separator:
appidAPP123methodrustici.registration.existsregid1234ts20171024213655
then prepend the secret key:
someverysecretkeyappidAPP123methodrustici.registration.existsregid1234ts20171024213655
then run that through MD5 to get the sig parameter:
bf38a2e6b2f9a97faf276a7075c9cbc2
which can then be used to build the API call string:
https://cloud.scorm.com/api?method=rustici.registration.exists&appid=APP123®id=1234&ts=20171024213655&sig=bf38a2e6b2f9a97faf276a7075c9cbc2
The order of the parameters in the URL is irrelevant; the server will perform the same sorting, concatenation, and MD5 process on its side and check if the signature matches the expected value for any of the enabled secret keys for that application. If not, the server will return the error:
The signature attached to the call does not match the signature generated on the server.
This error could mean many different things:
- the secret key might be incorrect for the app ID in the request
- not all parameters in the URL were included in the calculation (all parameters in the URL must be)
- the sorting algorithm did something incorrect (perhaps it was case sensitive, whereas the algorithm is specified as case-insensitive sorting)
- there were unexpected characters (perhaps a stray newline or space at the beginning or end)
- it was encoded in something other than UTF-8
- or any other error that makes the signature mismatch
Note
Here because you received the signature error while using one of our client libraries? That almost certainly means you’ve got the wrong secret key for the app ID you’ve chosen. Contact us at support for help if things still seem wrong.
Sample Implementation
Here’s a sample implementation of the signing algorithm taken from the Python client library and simplified:
from hashlib import md5
def encode_and_sign(appid, secret, params):
"""
URL encodes the data in the params dictionary, and signs it using the
given secret, if a secret was given.
Arguments:
- appid -- the application ID
- secret -- a secret key for that application
- params -- dictionary containing the key/value parameter pairs
"""
params['appid'] = appid
params['ts'] = datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S")
signing = ''
values = list()
for key in sorted(list(params.keys()), key=str.lower):
signing += key + params[key]
values.append(key + '=' + urllib.parse.quote_plus(params[key]))
sig = md5(secret.encode('utf8') + signing.encode('utf8')).hexdigest()
values.append('sig=' + sig)
return '&'.join(values)
The function takes an input like:
encode_and_sign('appid', 'some secret', { 'method': 'rustici.registration.exists', 'regid': '123' })
and returns a string like:
"appid=...&method=rustici.registration.exists®id=123&ts=...&sig=..."