User Guide
Developer Guide
API Guide
Developer Guide Contents

Introduction

Quoting the user guide provides a nutshell description of the SignSpace service: 

SignSpace is a business platform for collaboration within and between organizations.

SignSpace allows organizations to share, refine, approve and manage any digital content in a secure way.

This developer guide explains how the features of the SignSpace service can be accessed via an application programming interface (API) and integrated to partners' solutions.

As the SignSpace service itself is developed using the API, the interface offers a full set of services for partners. However, our aim is not to kickstart the development of multiple parallel implementations of the service, rather than to concentrate on key interfaces that existing and future backend systems can utilize:

The full SignSpace API documentation will be released in Q4 of 2018.

Technology overview

SignSpace is built with commonly used technology components and methods. The following listing describes the key elements of the developer-visible offering and provides a selection of documentation links. 

Component More information
REST - representational state transfer wikipedia
JSON - Javascript object notation wikipedia
OAuth - Open authorization framework wikipedia

The SignSpace API is platform-agnostic, it can be used in all platforms that support the HTTP-protocol.

Primary communication channel

In order to ensure that the we get the maximum amount of infromation on how SignSpace works in everyday communications, we have chosen to use it for most communications with partners during the pilot project. 

Welcome!

This is an exciting moment for us as SignSpace developers, and we are thrilled to have you with us on this ride.

Please let us know if you spot any omissions, inconsistencies or any other issues in the service or the documentation. 

Authentication

Currently SignSpace uses a temporary authentication-scheme, which shall be superseded by the OAuth-based mechanism in Q4 of 2018. 

Practicalities

Where is the SignSpace service? 

The partner-environment is located at:

https://signspace.beta.tilaajavastuu.fi

The production environment is located at:

https://signspace.fi

For ease of use and brevity, the document hereafter uses a variable to refer to the used environment:

export URL=https://signspace.beta.tilaajavastuu.fi/api/v1

How do I get access to SignSpace service? 

Create an account for yourself in the service using the user interface.

How do I get a token to use the SignSpace API?

Until the authentication endpoints are available, the easiest way to obtain a token is to use a web browser's development tools to capture the token from the SignSpace-cookie (the attached figure shows how the tools look like in Chrome).

Obtain token from

Now you have a user-specific token string. As the following chapter explains, when used with curl, it is most easily stored in an environment variable.

export SESSION_ID=value

How long is the token valid? 

For an hour. 

Resources

You can access the elements of the data model of the SignSpace service via resources in the API. A resource corresponds to a noun in a sentence, such as "message" or "user", that you operate on via the supported HTTP verbs. An singular uniquely identified individual entity that you operate on is called a resource instance (in this context the term essentially interchangeable with "object"). The "id"-property is used as to identify the individual resource instances and to refer to them.

The API does not provide an 1:1 mapping to the underlying data model. Hence it acts as an insulation layer between the implementation of the service and the integrations using it. This essentially enables large-scale changes within the SignSpace service without any effect on the interface and thus need for changes in the integrations. 

The key resources are as follows:

Resource Description
Message A message is sent by its author to one or more recipients. A messages is either an assigned task, a signing request for a single document, or just plain text. Any message may contain attached pdf documents or images, only pdf documents can be requested to be signed.
Thread A thread consists of a message and its replies. A thread may contain messages of different types. A thread has an access level, which determines to whom its messages may be sent.
File The maximum size of a file is 25 megabytes.
Group A space is a domain for threads and users. A space is typically to establish a context, e.g. all communications related to a project or a customer case.
User A person who is able to login to SignSpace and utilize its features.
Organization A collection of users that use the same e-mail domain.

The API is REST-like, with rather definite remote procedure call overtones (method names explicitly define the functionality).

Each resource instance is identified with an unique string. And accessed as follows:

$URL/files.get?id=$FILE_ID

Parameters

As noted in resources, identifiers are always carried in the path of the request URL. 

Body parameters are used in POST, PUT and PATCH methods. Missing required parameters are flagged with a Bad Request-error. 

Query string parameters can be used to tweak the returned responses. 

List-parameters

When calling endpoints that return lists, the following query parameters can be used to control the results:

As an example, the following call provides up to twenty messages that start from the 21st message in the user's inbox: 

/users/me/messages?offset=20&limit=20

Examples

< FIXME: entire contents after the production authentication is available > 

This page lists several examples that can serve as starting points for development.

The examples are done using curl, and the resulting JSON-documents have been prettyprinted using jq (results seriously abbreviated, since the data elements used in the responses contain a lot of properties). 

The examples assume availability of a base64-encoder (in order to upload a file).

The examples assume that environment variables are used to store tokens and identifiers as described above and as follows:

Other environment variable are introduced as they become available in SignSpace responses.

Also, validating the results in the SignSpace service (e.g. new messages appear, state of a task changes) is an excellent way to familiarize yourself with the behaviour of the service.

The personal details used in the examples have been changed.

Login

TODO: AFTER THE AUTHENTICATION WORKS

Get all messages addressed to me

This is the most basic scenario and essentially establishes that you've set up your client correctly.

curl -XGET -H "Cookie: ss_session_id=$SESSION_ID" "$URL/conversations.list"

And the response, an array of messages starts like this:

[
  {
    "time": "2018-10-09T18:24:31",
    "creator_handle": "5b8a599e2854098c289e3d27",
    "owners_handles": [
      "5ba88bebd8d5a1008125d2f8"
    ],
    "owners_orgs_ids": [],
    "members_handles": [
      "5ba88bebd8d5a1008125d2f8"
    ],
    "available_to_handles": [
      "5ba88bebd8d5a1008125d2f8"
    ],
    "forwarded_message": null,
    "subject": "Welcome to SignSpace!",
    "type": "thread",
    "draft_text": null,
    "is_draft": false,
    "is_protected": false,
    "security_settings": {
      "verified_identities_required": false,
      "content_sharing_disabled": false,
      "message_preview_disabled": false
    },
    "created_at": "2018-10-09T18:24:31",
    "published_at": "2018-10-09T18:24:31",
    "last_message_combined_text": "Welcome to SignSpace! ...",
    "messages_count": 1,
    "orgs_settings": [
      {
        "org_id": null,
        "approvals_required": true
      }
    ],
    "_id": "5bbcf25f22100e0023891164",
    "requires_action_from_me": false,
    "starred_by_me": false,
    "mentions_me": false,
    "archived_by_me": false,
    "unread_by_me": false,
    "unread_by_me_and_mentions_me": false,
    "has_attachment": false,
    "title": "",
    "is_restricted": false,
    "members_text": "You"
  }
]
 

The most interesting property of the individual messages is the _id-field, which enables operating on that particular message.

export MESSAGE_ID=5bbcf25f22100e0023891164

Get a document signed by another user

This flow involves multiple steps and is the core of the integration of the signing implementation.

The flow creates a new thread for the signing request message.

First, define a handle for the user that sends the request:

export HANDLE="firstname.lastname@organization.com"

The second step is to upload the file to be signed into SignSpace. The file must be base64-encoded, the attached example encodes the document on the fly, but obviously the file can be attached in an already encoded form.

curl -XPOST -H "Cookie: ss_session_id=$SESSION_ID" -H "Content-type: application/json" -d '{"acting_handle": "'$HANDLE'","base64": "'$(cat ./lemur.pdf|base64)'","name": "Puoliapinan kuva"}' "$URL/files.create"

The response shows the newly uploaded file.

          {
            "file": {
              "time": "2018-10-24T08:54:38",
              "creator_handle": "5ba88bebd8d5a1008125d2f8",
              "owners_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "owners_orgs_ids": [],
              "available_to_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "parent": null,
              "file": "5bd0334e7f5ef42259de91db",
              "name": "File #4",
              "hash": "86b8f001c4f6ac81afb2e5b57006591b5d1324d715d61ccecb46e94a807584ee",
              "content_type": "application/pdf",
              "created_at": "2018-10-24T08:54:38",
              "is_dir": false,
              "is_public": true,
              "is_hidden": false,
              "size": 71151,
              "_id": "5bd0334e7f5ef42259de91dd",
              "size_human": "69.5 kB"
            },
            "status": "ok"
          }

The file id will be used in the following steps, so capture it into a variable:

export FILE_ID=5bd0334e7f5ef42259de91dd

As expected, the properties of the file are available through the API as well:

curl -XGET -H "Cookie: ss_session_id=$SESSION_ID" "$URL/files.get?id=$FILE_ID"

The signing request is created as follows, use as many handles for participants as is needed:

curl -XPOST -H "Cookie: ss_session_id=$SESSION_ID" -H "Content-type: application/json" -d '{"files": ["'$FILE_ID'"],"title": "Signing request","description": "Please sign the attached document","acting_handle": "'$HANDLE'","participants": [{"handle": "'$HANDLE'","role": "signer"}]}' "$URL/tasks.signingRequest.create"

The response shows the status of the request.

          {
            "status": "ok",
            "task": {
              "time": "2018-10-24T08:59:04",
              "creator_handle": "5ba88bebd8d5a1008125d2f8",
              "owners_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "owners_orgs_ids": [],
              "available_to_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "unread_by_handles": [],
              "title": "Allekirjoituspyyntö",
              "description": "Allekirjoittakaapa oheinen tiedosto",
              "type": "signing_request",
              "completion_type": "all",
              "participants_list_is_flexible": false,
              "participants_list_order_respected": false,
              "status": "open",
              "due_date": null,
              "action_required_from_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "participants_handles": [
                "5ba88bebd8d5a1008125d2f8"
              ],
              "mentions_handles": [],
              "participants": [
                {
                  "_id": "5bd0345722100e277f079dbc",
                  "handle": "5ba88bebd8d5a1008125d2f8",
                  "position": 0,
                  "role": "signer"
                }
              ],
              "files": [
                "5bd0334e7f5ef42259de91dd"
              ],
              "must_be_reviewed_before_signing": false,
              "signing_request": "5bd0345822100e277f079dbe",
              "_id": "5bd0345822100e277f079dc3",
              "mentions_me": false,
              "requires_action_from_me": true,
              "starred_by_me": false,
              "unread_by_me": false,
              "archived_by_me": false,
              "unread_by_me_and_mentions_me": false,
              "has_attachment": true,
              "access_request_type": "none",
              "description_plain": "Allekirjoittakaapa oheinen tiedosto"
            }
          }

Store the request id as follows:

export REQUEST_ID="5bbf42b7070201001d93dee6"

Create a new thread for the request:

curl -X POST -H "Cookie: ss_session_id=$SESSION_ID" -H "Content-type: application/json" -d '{"subject": "Request test","acting_handle": "'$HANDLE'","type": "thread","creator_handle": "'$HANDLE'","is_protected": false,"owners_handles": ["'$HANDLE'"],"members_handles": ["'$HANDLE'"],"orgs_settings": [{"org_id": null,"approvals_required": false}]}' "$URL/conversations.create"

The response shows the thread.

        {
          "status": "ok",
          "conversation": {
            "time": "2018-10-24T09:02:39",
            "creator_handle": "5ba88bebd8d5a1008125d2f8",
            "owners_handles": [
              "5ba88bebd8d5a1008125d2f8"
            ],
            "owners_orgs_ids": [],
            "members_handles": [
              "5ba88bebd8d5a1008125d2f8"
            ],
            "available_to_handles": [
              "5ba88bebd8d5a1008125d2f8"
            ],
            "trans_context": {},
            "forwarded_message": null,
            "subject": "Request test",
            "type": "thread",
            "draft_text": "",
            "is_draft": true,
            "is_protected": false,
            "security_settings": {
              "verified_identities_required": false,
              "content_sharing_disabled": false,
              "message_preview_disabled": false
            },
            "created_at": "2018-10-24T09:02:39",
            "published_at": null,
            "messages_count": 0,
            "orgs_settings": [
              {
                "org_id": null,
                "approvals_required": false
              }
            ],
            "_id": "5bd0352f0702011e53cd0a1a",
            "requires_action_from_me": false,
            "starred_by_me": false,
            "mentions_me": false,
            "archived_by_me": false,
            "unread_by_me": false,
            "unread_by_me_and_mentions_me": false,
            "has_attachment": null,
            "is_restricted": false,
            "last_message_combined_text": "",
            "members_text": "You"
          }
        }

Store the thread id as follows:

export THREAD_ID="5bbf42b7070201001d93dee6"

Finally, create a message in the thread that contains the siging request

curl -X POST -H "Cookie: ss_session_id=$SESSION_ID" -H "Content-type: application/json" -d '{"conversation": "'$THREAD_ID'","acting_handle": "'$HANDLE'","text": "Tämä on Sähköinfon lähettämä allekirjoituspyyntö." ,"attachments": {"tasks": ["'$REQUEST_ID'"]}}' "$URL/conversations.postMessage"

The request is now visible and operable in the SignSpace user interface.

Logout

TODO: after OAuth-endpoints are available

Best Practices, common questions & pitfalls

To be initiated and extended throughout the pilot period as questions and issues are resolved.

Return values & errors

Each endpoint returns headers (including an HTTP status code [see IANA for canonical definitions]) and a JSON document (exceptions are noted per-endpoint in the API documentation, e.g. a successful DELETE-call returns only a status code, no document body at all) . 

If the status code indicates an error, the response contains a JSON document that provides ahuman-readable explanation about the encountered fault.

In some cases the error is returned by the frameworks utilized by SignSpace, and the returned contents may differ.

Note that success in an operation is determined by the nature of the operation, and a "200" is not an universally applicable indication of success (again, see API Documentation for details). 

Common error situations 

Status code

Explanation

400 Bad request - the request is missing a required parameter, a supplied parameter has a syntactically invalid value, or a combination of parameters is semantically invalid.
401 Unauthorized - the user named in the request is lacking privileges to complete an action (e.g. sign a documemnt).
402 Payment Required - the parameters of the contract have been exceeded and e.g. the number of licensed users needs to be increased. This is not in use yet.
403 Forbidden - the user named in the request is not present in SignSpace-service or is lacking privileges to complete an action (e.g. add an user to a space).
404 Not found - the requested resource instance is not present in the SignSpace-service.
408 Request Timeout - Internal timeout.
409 Conflict - Error updating a resource instance in the database.
429 Too Many Requests - the integration has sent too many requests recently. This is not in use yet.
500 Internal Server Error - attempting to serve the request has failed.

Especially with error code 500, please let us know what the circumstances of an observed fault are.

Throttling

SignSpace no throttling functionality implemented yet. 

Nonetheless, the integrations should utilize common sense and pace themselves when submitting multiple requests.

Even if there's no mechanism to prevent their creation and existence, we strongly suggest that integrations do not maintain unnecessary parallel connections. 

However, throttling is definitely a roadmap item, so HTTP status code 429 will be introduced in the future. 

Timeouts

As noted in the errors section, a timeout is announced with an explicit status code.

However, as a timeout may occur in network infrastructure outside of SignSpace, the response may vary depending on the origin (and thus not contain the any human-readable explanation on what happened). 

Downtime

Planned downtimes are announced in advance on the forthcoming SignSpace blog and the ss_dev_common-space in the SignSpace service.

Contracts

Every SignSpace customer operates within the parameters of a contract;.

As noted in the errors section, a an interaction by the customer that would exceed the contractual parameters returns an appropriate status code and the message-body contains a human-readable description about the exceeded parameter (if multiple parameters would be exceeded with a single interaction, at least one of them shall be identified in the message). 

Support

Developer support uses the same channels as the SignSpace service (customer service and communications within SignSpace) to initiate issue resolution.

However, as practices and processes evolve during the pilot phase of SignSpace, additional means to address issues in more streamlined fashion may emerge. This page shall be kept up to date as the support schema evolves. 

Please be as precise as feasible when reporting errors: the request and response messages (or lack of a response) and an approximate timeframe of the discovered error are most helpful in resolving the issues in a timely and efficient manner.

Versioning

SignSpace API is developed with a "maximally downwards-compatible"-scheme. As JSON is a flexible way of transferring content, the following updates are possible without breaking compatibility: 

The API version is included in the request path, and upon a non-backwards-compatible update shall be changed from /v1 to a new version.

To upgrade an integration requires changing the version identifier in the request. 

In general the deprecation of previous API versions shall be announced well in advance of the actual change (the communications and procedures on this shall be developed during the pilot phase).

Roadmap

The SignSpace roadmap is essentially divided into two main categories, with the productization of the service as the watershed between the two. A lot of the roadmap elements concern user interface improvements, but additional interfaces and related features are included.

How do I propose features for the roadmap? 

Use the existing communication channels (preferably the spaces in SignSpace) to describe your needs and ideas for enhancements of SignSpace or its developer offering.