Developer Guide
Learn how to access and integrate SignSpace service via an application programming interface (API).
Introduction
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.
The comprehensive SignSpace API documentation will be released in Q2 of 2022.
The identities of users and API clients are maintained using Gluu identity provider.
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 |
|
JSON - Javascript object notation |
|
OAuth - Open authorization framework |
The SignSpace API is platform-agnostic, it can be used in all platforms that support the HTTP-protocol.
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 & Practicalities
Where is the SignSpace service?
The partner-environment API is located at: https://signspace.beta.tilaajavastuu.fi/api/v1
The production environment is located at: https://app.signspace.com/api/v1/
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 the SignSpace service?
Create an account for yourself in the service using the user interface.
The OAuth2 client credentials grant mechanism is used for authentication.
Please send your request for client credentials to partnerit@tilaajavastuu.fi. We will relay you the required values.
The identity provider for partner-environment is located at: https://signspace.beta.tilaajavastuu.fi/auth/token
Again, for convenience, fetch and store the token in an environment variable, after defining the values of CLIENT_ID and SCOPES-variables according to the response from the customer service:
curl -X POST --user $CLIENT_ID -d "grant_type=client_credentials&scope=$SCOPES" https://signspace.beta.tilaajavastuu.fi/auth/token
Afterwards, use the received access token in the request as follows:
curl -X GET -H "Authorization: Bearer $TOKEN" "$URL/conversations.list"
How do I get user-specific access token?
The client credentials-flow authorizes the client program to access SignSpace API, but does not authenticate any particular user.
For that functionality the OAuth2 authorization code grant would be used instead.
The operative words being "would be", full support for authorization code grant is a roadmap item currently, and we will update this page when it is available for use.
What e-mail address should I use on beta?
The beta-environment is aggressively whitelisted. Please use a mailinator.com address.
What kind of data should I use on beta?
Do not use your personal details. Do not upload any business-critical documents.
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 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 message 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. |
Space |
A space consists of a message and its replies. A space may contain messages of different types (plain messages, tasks and signing requests). A space 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 group is a collection of users (and groups). A group 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 utilise its features. |
Organisation |
A collection of users that use the same email 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
Parametres
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-parametres
When calling endpoints that return lists, the following query parameters can be used to control the results:
- offset - the number of the resource instance from which the returned list starts,
- limit - the maximum number of resource instances returned in the list (defaults to 20),
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
This page is the first key flow as a starting point 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 export TOKEN=the value as captured in the Authentication-chapter.
Other environment variables 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 familiarise yourself with the behaviour of the service.
The personal details used in the examples have been changed.
Get all messages addressed to me
This is the most basic scenario and essentially establishes that you've set up your client correctly.
curl -X GET -H "Authorization: Bearer $TOKEN" "$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,
"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 space for the signing request message.
The flow is as shown in the following figure, in essentially two phases: first retrieve an access token, and then call the SignSpace API with that token.
First, define a handles for the integration robot that sends the request and for the signatory:
export BOT_HANDLE="robot handle supplied by SignSpace"
and create another handle for the recipient of the signature request:
export SIGNATORY_HANDLE="firstname.lastname@domain.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 -X POST -H "Authorization: Bearer $TOKEN" -H "Content-type: application/json" -d '{"acting_handle": "'$BOT_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 -X GET -H "Authorization: Bearer $TOKEN" "$URL/files.get?id=$FILE_ID"
The signing request is created as follows, use as many handles for participants as is needed:
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-type: application/json" -d '{"files": ["'$FILE_ID'"],"title": "Signing request","description": "Please sign the attached
document","acting_handle": "'$BOT_HANDLE'","participants": [{"handle": "'$SIGNATORY_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": "Please sign the attached document",
"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": "Please sign the attached document"
}
}
Store the request id as follows:
export REQUEST_ID="5bbf42b7070201001d93dee6"
In order to specify the language used in communications with signatories and other recipients, use the following optional parameter in the request:
"recipient_language": "fi"
In order to specify the signature strength (i.e. whether a signatory is required to strongly authenticate), use the following optional parameter in the request:
"signature_strength": "strong"
Create a new space for the request:
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-type: application/json" -d '{"subject": "Request test","acting_handle": "'$BOT_HANDLE'","type": "thread","creator_handle": "'$SIGNATORY_HANDLE'","is_protected": false,"owners_handles": ["'$BOT_HANDLE'"],"members_handles": ["'$SIGNATORY_HANDLE'"],"orgs_settings": [{"org_id": null,"approvals_required": false}]}' "$URL/conversations.create"
The response shows the space.
{
"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 conversation id as follows:
export THREAD_ID="5bbf42b7070201001d93dee6"
In order to avoid extra notification emails being sent to signatories and other participants, you can use the following optional parameter in the request
send_notifications: false
Finally, create a message in the conversation that contains the signing request
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-type: application/json" -d '{"conversation": "'$THREAD_ID'","acting_handle": "'$BOT_HANDLE'","text": "This is a signature request sent by company X." ,"attachments": {"tasks": ["'$REQUEST_ID'"]}}' "$URL/conversations.postMessage"
The request is now visible and operable in the SignSpace user interface.
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 possible, 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 a human-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.
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 document). |
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 has 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 any human-readable explanation on what happened).
Downtime
Planned downtimes are announced in advance on the SignSpace blog.
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
Please use the partnerit@tilaajavastuu.fi e-mail address to report discovered bugs and other issues.
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:
- adding new resources
- adding new fields to a resource
- adding new values to an enumerated field
- adding new optional parameters to request.
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 suggest 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.