English

Autenti API Documentation

You can see a collection in PostMan by clicking a button below.
 
Revision: 2021-07-06
The document should be read in conjunction with formal Open API 3.0 specification for Autenti API v2, available at: https://app.swaggerhub.com/apis/Autenti.com/Autenti-Document-Process-API/v2-bespin
The Open API 3.0 specification contains a full list of exposed API endpoints as well as definitions of structures used in communication, as well as an extended set of examples.

API Purpose

Documents signing is typically just a part of some larger process, usually leading to the conclusion of some contract between people and institutions. This a larger process is interacted with using existing tools of given institution, such as an application management system (eg. loan application management system). It is useful to handle the preparation of the document and signing it within such a tool or system, without dependency on tools external to the organization, i.e. the Autenti signature front end.
A method an organization’s system, a software application a user uses to perform functions related to sending documents to signers and signing them, can interact with Autenti systems, is via the so-called integration interface, commonly referred to as API (Application Programming Interface). API allows external applications to query and command Autenti systems. An external application acts on behalf of Autenti system users but presents Autenti system capabilities in a way specific to itself (for example as part of applying for a loan).
This document describes the assumptions of the integration interface, the way of enabling foreign systems to access Autenti, including self-registration procedures so that actions by those systems are attributable to them and a certain level of trust in those systems reflected by permissions, the scenarios of achieving given results with the API, and finally they way external systems can be kept informed about the events in the Autenti systems so that they can react and progress their own processes based on the progression of the process under Autenti management.

Assumptions and design principles

The assumptions and design principles listed below were observed when designing the integration interface (API):
  • the transport protocol is HTTP, version 1.1 and / or 2
  • whenever practical the API is designed as RESTful, maturity level 2 (Richardson’s model)
  • it was deliberately decided not to attempt using HATEOAS self-describing API design (Richardson maturity level 3)
  • the API will include asynchronous callback channel to allow subscribing to events. the list of events is an open one, and the structure of the event generic (with open attributes list)
  • the API is only available to known a priori client applications, registered by Autenti, and Autenti reserves the right to refuse to register (and thus: grant access) any application, as well as revoke access to the API at any time
  • all API queries and actions require authentication, and no API operations are possible in anonymous context

Requirements concerning the applications accessing the API

The clients of the API are required to react in consistent and user friendly manner to the API returning new dictionary values unknown to the client (introduced after the client application was integrated), in particular be prepared for:
  1. new kind of participant in the process (for example, a client written when the only participants possible in the process were signers, should properly function with documents with new “approver” participant - while may not be able to perform the actions possible for approver - while even that is made possible by the use of challenge-action-assertion mechanism, see: The challenge-action-assertion model
  2. new constraints describing the way a given participant is restricted, for example requiring additional, new authorization mechanism to be used before accessing the document (constraints that depend on user action will result in challenges to be raised by the API if the action constrained is attempted, giving the connected application a chance of reacting to that constraint, including by interacting with the user)
  3. new kind of challenges describing required interaction between Autenti, its client, and the user of the API
Autenti reserves the right to forbid access by any and all applications not written according to the principles above, most importantly written in a way that would result in describing a failure of the application to adapt to extensions to the API described above - as an error. For example, if a document using a new type of constraint securing access to the document is returned to the application, the table below shows acceptable and unacceptable ways of describing this situation to a user:
Unacceptable way Correct way

There was an error processing the document

Unsupported feature detected. Please use Autenti system to continue.

Unknown error

Handling of this document requires newer version of this application

Getting started

Getting access to the API

For the external application to access the API it needs to be registered in the Autenti system, and its identifying credentials issued upfront. The registration can be performed by super-administrators in the web interface of Autenti, or via OAuth 2.0 Dynamic Client Registration Protocol.
OAuth 2.0 Dynamic Client Registration Protocol API, can only be called by superadmins, and superadmins can authenticate themselves to the API using well-known default cbootstrap application client credentials (client_id: autenti, client_secret: autenti).
At the time of writing the API is only available for organization accounts with subscription plan Pro (subject to change).

Client application registration using management user interface

The application registration process can be performed by a user with “superadmin” role in the management panel of Autenti system. After registration the application is assigned a unique identifier called client_id and a corresponding secret called client_secret (see ttps://tools.ietf.org/html/rfc6749#section-2.3.1). Client secrets are generated automatically by the Autenti system, and cannot be set arbitrarily. The client secret can be re-generated on demand, for example, if compromised, and the option is available in the management user interface (company management panel).

Client self-registration with OAuth 2.0 Dynamic Client Registration Protocol

OAuth 2.0 Dynamic Client Registration Protocol RFC 7591 - OAuth 2.0 Dynamic Client Registration Protocol endpoints enable “superadministrators” to register external applications as clients of the API.
At the time of writing only a subset of properties defined by the protocol are available:
The registration endpoint returns (if API access is enabled for the organization and the superadmin user is properly authenticated) the client_id and client_secret of the newly registered client application. It is the only moment (except for requesting re-generation of a new client_secret) the client secret is returned by the API (one will not be able to retrieve it again, but may request re-generation)
Bootstrap client
To register a client application a user needs to authenticate to Autenti system (as a superadmin of an organization - see API user authentication and API call authorization). To do that via API, a client application is needed - a chicken and egg problem. Autenti offers a pre-registered bootstrap client application, available for all companies.
The only scopes that can be requested using this client application are client_management and notification_management. Any scopes outside of this list are be silently ignored, even if requested, and the issued token does not include them (no error will be returned, just the scopes will not be there on the authorized scopes list).
So, to register a client application via API the sequence of requests can be used:
Authorization request for a superadmin, using the bootstrap client application, requesting client_management scope:
POST https://api.autenti.com/api/v2/auth/token
Content-Type: application/json

{
  "client_id": "autenti",
  "client_secret": "autenti",
  "grant_type": "password",
  "username": "superadmin@company.fake.com",
  "password": "iMpossible_TO_GueSSS",
  "scope" : "client_management"
}
Important
The example above uses password grant. This grant type is not generally available to client applications, and (unless Autenti allows otherwise) can only be used with the bootstrap client.
Autenti supports, and advise, to use a regular OAuth2 Authorization Code Flow for superadmin authentication and authorization, as described in API user authentication and API call authorization, but allows a simplified flow, as we recognize the difficulties in the early stages of integration - which registering the first client application belongs to.
A successfull bootstrap authorization token response
HTTP/1.1 200 OK
Date: Sun, 28 Feb 2021 15:07:17 GMT
Content-Type: application/json

{
  "scope": "client_management",
  "access_token": "eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiZGlyIn0..hkkQ0kT-CzoT5nMb1EGV_0Y.EEakj94VQpB5VMSM-w4mLQ",
  "token_type": "bearer",
  "expires_in": 1770,
  "refresh_token": "eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiZG..RImnLpeHyCpYkg"
}
Important
Please note Autenti uses self-contained tokens of significant length. Please ensure at least 1500 characters reserved to store tokens.
With a newly generated access token the OAuth2 Dynamic Client Registration protocol endpoitn can be used to create a new client application for your company:
Request for creation of a new client application
POST https://api.autenti.com/api/v2/clients
Authorization: Bearer eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiZGlyIn0..hkkQ0kT-CzoT5nMb1EGV_0Y.EEakj94VQpB5VMSM-w4mLQ
Content-Type: application/json

{
  "redirect_uris": [
    "https://postman-echo.com/get"
  ],
  "client_name": "Fake Corp. Autenti Client",
  "scopes": [
    "read", "list", "read_one"
  ]
}
Important
Reserves some API scopes to be only available to selected applications. Some scopes can only be granted to an existing application (and will be silently ignored, if requested), after Autenti audit of the application. Autenti reserves the right to unilaterally grant (following the audit process), and withdraw, without the need of justification, access to the following scopes:
  • signature_via_api
  • approval_via_api
  • review_via_api
New client creation and notification management is only possible using pre-defined bootstrap application (and may be in the future granted to selected partner applications)/ The scopes listed below will be silently ignored if requested via API for a newly created client application:
  • notification_management
  • client_management
A successfull client application creation response
HTTP/1.1 200 OK
Date: Sun, 28 Feb 2021 15:07:17 GMT
Content-Type: application/json

{
  "client_id": "9e7629c4-4246-4b17-8315-4578ae212660",
  "client_secret": "dfbc3a80-93be-4138-805d-f5e0c7661d6d",
  "client_secret_expires_at": 0,
  "redirect_uris": [ "https://postman-echo.com/get" ],
  "client_name": "Fake Corp. Autenti Client",
  "scopes": [ "read", "list", "read_one" ]
}
Important
Please note that a client secret value is only returned when a new secret is created (either when a new application is registered, or a secret re-generated). The secret cannot be retrieved by querying the client application information, nor is communicated in any other channel.

API user authentication and API call authorization

As the user of an external application is effectively isolated from the Autenti system by such application, it is required the user is authenticated to the Autenti system so that any actions performed by the external application can be correctly associated with the user’s account (and to enforce proper access control measures, for example to prevent access to the documents not meant for given user). The system uses OAuth2 as the authorization mechanism, and all API calls expect standard HTTP 1.1 “Authorization” header containing a “bearer” token (see: https://tools.ietf.org/html/rfc6750#section-2.1 ).
The process of issuing an authorization token is strictly OAuth2 compliant, in one of:
Of the above, only authorization code flow and refresh token grant will be universally available to external applications, use of other flows will be limited to trusted clients based on bilateral agreement and security audit.

Example API authorization with OAuth2 authorization code flow (line breaks for display purposes only)

Authorization request:
curl -X GET --location "https://api.autenti.com/api/v2/auth/authorization" \
--data-urlencode "response_type=code" \
--data-urlencode "client_id=5a8806ef-a7ac-4467-834f-36f5e5471012" \
--data-urlencode "redirect_uri=https://acme.com/redirect" \
--data-urlencode "scope=full" \
--data-urlencode "state=U3VuIEphbiA"
If the request is accepted (known client, scope available for given client, acceptable flow, redirect_uri whitelisted for this client), the response will contain the redirect to login pages of Autenti:
HTTP/1.1 302 Found
Location: https://accounts.autenti.com/login?state=erhjwifvhwihvw3248vw8fh4jrvn35ewe5n5u5
After successful login (on Autenti login pages), the user browser will be redirected to the requested redirect_uri, and the code parameter will contain the code that can be exchanged for the authorization token at the /token endpoint (see next section). The state parameter is also returned, if given originally in the authorization request:
HTTP/1.1 302 Found
Location: https://acme.com/redirect?code=hwAUwvu2345sdfsfg344324dgH6&state=U3VuIEphbiA
The code returned shall be used by the backend (to avoid revealing the client_secret by using it at a client side) to call the /api/v2/auth/token endpoint:
Token request with authorization code:
curl -X POST --location "https://api.autenti.com/api/v2/auth/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=authorization_code" \
    -d "client_id=5a8806ef-a7ac-4467-834f-36f5e5471012" \
    -d "client_secret=22e99dd6-b70e-4dee-80bf-fb728f256df9" \
    -d "redirect_uri=https://acme.com/redirect" \
    -d "code=hwAUwvu2345sdfsfg344324dgH6"
Successful response will contain an authorization and refresh token:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
    "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
    "token_type":"bearer",
    "expires_in":3600,
    "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
    "scope":"full"
}

Example API authorization token refresh

Authorization tokens are relatively short lived (at the time of writing authorization tokens are valid less than 1 hour). To maintain access to the API a refresh token can be used - this minimizes impact of a leaked access token. Refresh token, even if leaked, can only be used with client credentials, thus is less prone to compromitation.
A token refresh request is a way to acquire a new authorization token, if the previous one was compromized, or expired.
Autenti currently assumes refresh tokens live for 24h from the moment of issuing them, so an application needs to refresh periodically. This might be changed for selected, highly trusted clients, or in the future, to support refresh tokens not to expire.
Token request with refresh token:
curl -X POST --location "https://api.autenti.com/api/v2/auth/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=refresh_token" \
    -d "refresh_token=IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk" \
    -d "client_id=5a8806ef-a7ac-4467-834f-36f5e5471012" \
    -d "client_secret=22e99dd6-b70e-4dee-80bf-fb728f256df9"
Successful response will contain an authorization token and a new refresh token:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
    "access_token":"r56Q0asg5OTM2NDE1ZTZjNGZmZd4",
    "token_type":"bearer",
    "expires_in":3600,
    "refresh_token":"g22ygg225Kg552hjKKweD",
    "scope":"full"
}

Key concepts and entities

The document process

Document process is the key concept of the system. A document process represents jointly the actions a set of nominated participants (see: Parties) can take on some document (see: Content), and a history of those actions, at a given point in time.
An example document process, illustrating a document process in progress, with two signers, and an approver
{
  "id": "DOCUMENT_PROCESS:ac842283-afd4-4e26-9873-2bf35bd89b42",
  "title": "Sailing boat rental agreement",
  "description": "Please review the terms and sign",
  "processLanguage": "en",
  "status": "PROCESSING",
  "parties": [
    {
      "party": {
        "id": "PARTY-PUBLIC_APPROVAL_PROCESS_ID:4060e833",
        "firstName": "Mark",
        "lastName": "Wazowski",
        "name": "Mark Wazowski",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "mark.wazowski@acme.com"
            }
          }
        ],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE",
            "party": {
              "name": "Acme Co.",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "898123432"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "President"
            }
          }
        ]
      },
      "role": "APPROVER",
      "participationStatus": "COMPLETED",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 1
          }
        }
      ],
      "currentUser": false,
      "participationEvents": [
        {
          "eventType": "APPROVAL",
          "timestamp": "2020-10-21T15:48:34.863Z"
        },
        {
          "eventType": "VIEWING",
          "timestamp": "2020-07-18T19:16:40.997Z"
        }
      ]
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:4060e833",
        "firstName": "John",
        "lastName": "Smith",
        "name": "John Smith",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "john.smith@acme.com"
            }
          }
        ],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE",
            "party": {
              "name": "Acme Co.",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "898123432"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Salesman"
            }
          }
        ]
      },
      "role": "SIGNER",
      "participationStatus": "COMPLETED",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 2
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        }
      ],
      "currentUser": true,
      "participationEvents": [
        {
          "eventType": "SIGNATURE",
          "timestamp": "2020-10-21T15:48:34.863Z"
        },
        {
          "eventType": "VIEWING",
          "timestamp": "2020-06-18T19:16:40.997Z"
        }
      ]
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:bdb551b2",
        "firstName": "Maurice",
        "lastName": "Chevallier",
        "name": "Maurice Chevaller",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "chevallier1981@gmail.com"
            }
          }
        ]
      },
      "role": "SIGNER",
      "participationStatus": "PENDING",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 3
          }
        }
      ],
      "currentUser": false
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:4060e833",
        "firstName": "John",
        "lastName": "Smith",
        "name": "John Smith",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "john.smith@acme.com"
            }
          }
        ]
      },
      "role": "SENDER",
      "participationStatus": "COMPLETED",
      "currentUser": true,
      "participationEvents": [
        {
          "eventType": "SUBMISSION",
          "timestamp": "2020-06-18T19:16:40.997Z"
        }
      ]
    }
  ],
  "contentElements": [
    {
      "id": "FILE-SOURCE_FILE:3cf4307e-63cc-4be9-b616-bd2b99d9778e",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "1",
      "modificationTime": null,
      "filePurpose": "SOURCE_FILE",
      "mimeType": "application/pdf"
    },
    {
      "id": "FILE-DTBS:ac842283-afd4-4e26-9873-2bf35bd89b42/DTBS",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "999",
      "modificationTime": null,
      "filePurpose": "PARTIALLY_SIGNED_CONTENT_FILE",
      "mimeType": "application/pdf"
    }
  ],
  "tags": [

  ],
  "flags": [
    "FLAG:VIEWED"
  ],
  "createdAt": "2020-06-18T19:16:40.997Z",
  "modifiedAt": "2020-10-21T15:48:34.863Z"
}

Parties

Parties represent people (in the future also: organisations) who take part in the process. The ways given person can participate (the actions one can take on a document process) are dictated by a party role.
At the time of writing there are three kinds of parties:
  • Individuals (people) - represented by Person structure
  • Organizations - companies and other legal entities, represented by Organization structure
  • Party groups - groups of parties, grouped by the expected way of participation (such as group of 5 signers, with 2 of them required to proceed), or representing a named group such a department of a company - reserved for future use
Parties can be linked to other parties, forming hierarchies. At teh time of writing there is only one type of relationship that can be described - the right to represent other party, and currently it is only supported to have an individual represent an Organization. The "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE" is the reserved type differentiator, and this relationship defines "relationshipDescription" attribute to describe the representative more specifically in a human readable form. At the current moment there are no other hierarchies describable(such as deeper hierarchies or hierarchies of individuals).
A party is included in the process based on the DocumentProcessParty declaration, naming its role in the process, listing any contraints that are applicable to the way the party can participate (for example: for a signer a desired type of signature can be specified, for any party - an expected order or priority of participation demanded, and so on).
A document process party example - a person (John Smith), who can be contacted at john.smith@acme.com with a right of representing an organisation Acme Co., with declared role of a "Salesman", to participate in the process as a signer, with relative priority 2 (after those with priority 1), and expecting to sign the document with a simple (BASIC) signature. John Smith has already signed, which is indicated by the participation status of COMPLETED (and the role of SIGNER), and the event with event type SIGNATURE.
    {
      "party": {
        "type" : "PERSON",
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:4060e833",
        "firstName": "John",
        "lastName": "Smith",
        "name": "John Smith",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "john.smith@acme.com"
            }
          }
        ],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE",
            "party": {
              "type" : "PERSON",
              "name": "Acme Co.",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "898123432"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Salesman"
            }
          }
        ]
      },
      "role": "SIGNER",
      "participationStatus": "COMPLETED",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 2
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        }
      ],
      "currentUser": true,
      "participationEvents": [
        {
          "eventType": "SIGNATURE",
          "timestamp": "2020-10-21T15:48:34.863Z"
        },
        {
          "eventType": "VIEWING",
          "timestamp": "2020-06-18T19:16:40.997Z"
        }
      ]
    }

Content

The purpose of the document process is to share some document between a group of people, and get them to act upon it. So, at the very core of the process is the content of the document. The content of the document has a form of a file or set of files.
The files are differentiated from one another by their "purpose".
Autenti accepts content from the process creator in one of several formats convertible to Portable Document Format (PDF). Those files are known as source files (and are marked as files with "SOURCE_FILE" file purpose). Addition of source files is a typical file upload to the
Source files are combined into one document, which is then presented in the process. This file is known as Data to Be Signed (DTBS) in official signature nomenclature. In Autenti process the document, until signed (approved, reviewed) by all required parties is marked with a file purpose of "PARTIALLY_SIGNED_CONTENT_FILE", and its ever changing version shows its changes as more partipants act on it (usually - by adding signatures).
Finally, the completed, fully signed and sealed document is marked with "SIGNED_CONTENT_FILE".
Additionally an archive with all the source and result files can be downloaded - and is described as a content file with "CONTENT_ARCHIVE" purpose.
An example set of files in a process
{
  "contentElements": [
    {
      "id": "FILE-SOURCE_FILE:3cf4307e-63cc-4be9-b616-bd2b99d9778e",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "1",
      "modificationTime": null,
      "filePurpose": "SOURCE_FILE",
      "mimeType": "application/pdf"
    },
    {
      "id": "FILE-DTBS:ac842283-afd4-4e26-9873-2bf35bd89b42/DTBS",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "999",
      "modificationTime": null,
      "filePurpose": "PARTIALLY_SIGNED_CONTENT_FILE",
      "mimeType": "application/pdf"
    }
  ]
}

Constraints

Constraint (limitation) is a way to describe additional requirements about the behaviour of parties or the process itself.
A way a participant is expected to take part in a process in dictated by the participant role (and document status, as no-one can sign a withdrawn document, you cannot have reviews till document is not sent etc.). If there are any other expectations and limitations to the way given party can act on a document - those are expressed as constraints (on a party level). Many constraints are a description of an additional security or verification mechanism (such as an expectation to use another identification factor other than a link received in an email), or are expression of the intention of the docuemnt creator (sender) about the desired way given participant is to act (for example - use specific kind of signature, and not just "sign").
Currently there are no constraint types defined on document level, but those can appear in the future (for example a document expiration time - if ever introduced - would be described as a document process level constraint).
Constraint example - limiting signature type a signer can use to sign - requirement of qualified signature
{
   "classifiers": [
      "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
   ],
   "attributes": {
      "requiredClassifiers": [
         "SIGNATURE_PROVIDER-SIGNATURE_TYPE:QUALIFIED"
      ]
   }
}
Constraints are on purpose defined generically, and share common structure. Most of the constraints that are defined on participant level are expectations of performing some additional action, or are influencing an action. As such even if a client application does not understand the way given constraint influences the process it is usually able to act on behalf of the user and still enable the user to participate in the process, as the constraints would result in a challenge when the constrained action is attempted (see: The challenge-action-assertion model).
The catalogue of constraints known at the time of writing (ever growing …​) is documented in the examples section of the OpenAPI specification (see: https://app.swaggerhub.com/apis/Autenti.com/Autenti-Document-Process-API/v2-bespin#). Unluckily the Open API format does not visualize examples section, please find appropriate part in the source of the specification.

The challenge-action-assertion model

Autenti API is by design made extensible, to support, without breaking existing clients, addition of new ways of interacting with the document process, as well as adding additional security checks. Also, new providers and integrations are being added every month.
Autenti used a relatively novel approach of using no prescribed request schema to describe any action desired, but rather to allow a user to express the intention of performing an action and instruct the application about all the steps required to perform this action.

An Interactive Voice Response system analogy

The best way to explain such API is by an example and analogy.
Imagine you have your document handling process made available via a telephone. The telecommunication system is your API, the phone (with its microphone, speaker, keyboard and screen) is your connected application. The Interactive Voice Response (IVR) is the backend. How could you request signing a document using such a system?
Step # IVR (says) User (does or says)

1

Good morning. You have 2 documents requiring your attention. Press 1 for document 1: "Loan agreement", Press 2 for document 2: "Account access proxy".

Pressed: 2

2

You can either: Press 1 to sign the document, Press 2 to reject the document

Pressed: 1

3

Your consent is required. Say "I consent" to accept the following statements: "I hereby confirm I have read the document titled 'Loan agreement' and agree with it. I want to sign the document". You can also press 1 to consent, or any other key to refuse the consent.

Says: "I consent"

4

Qualified signature is required. You can either: Press 1 to use Infocert signature, or Press 2 to use SimplySign signature

Pressed: 1

5

You have two known certificates: Press 1 to select certificate with ID: "My main certificate", Press 2 to select certificate with ID: "My other certificate", Press 0 to provide other certificate

Pressed: 2

6

A text message was sent to your phone number ending with 132. Please key in the digits of the code in the message, followed by #

Pressed: 2812#

7

We will require you to enter unique process id later. Please write it down: 52234555. Press 1 to continue, or 9 to repeat.

Pressed: 1

8

We have gathered all the information required to sign the document. Please type the unique process id you have written down followed by # to continue with signing (irrevocable!), hang up or press # to abort.

Pressed: 52234555#

9

Processing your request. please stay on the line. […​] Document signed successfully.

Disconnected

Our API allows to do a very similar thing: to interact with a document handling process, without knowing it a priori, and knowing all the possible options, depending on a user ability to understand the description and instructions given to him/her (but can, provided fallback mechanism is also made available, code to react to specific challenges in a very specific way). Let’s go through the steps described above, and illustrate them with API calls and responses (requests simplified, not mentioning all the headers, content of long responses etc., for clarity):
Let’s start with getting some information about documents we can act upon: We shall get a list of documents, depending on the requested format either as a stream of potentially unbounded length:
GET /document-processes?status=PROCESSING
Authorization: Bearer [token]
Content-Type: application/stream+json
or, in a more traditional, paginated form (streams can be returned with a limit, too)
GET /document-processes?status=PROCESSING&limit=50
Authorization: Bearer [token]
Content-Type: application/json
A collection of document processes (most of document description omitted for brevity)
HTTP/1.1 200 OK
Date: Sun, 31 Jan 2021 12:56:12 GMT
Content-Type: application/json
[
    {
        "id" : "DOCUMENT_PROCESS:528aa336-46a0-470f-b861-948fa8625455",
        "title" : "Loan agreement"
    },
    {
        "id" : "DOCUMENT_PROCESS:18beb9f0-7bcf-46ae-b4ff-bccac473d274",
        "title" : "Account access proxy"
    }
]
Once we have identified a document we are interested in, we can request to act upon it. Here is where the magic begins - the request to act upon the document does not need to describe actually how to act.
POST /document-processes/DOCUMENT_PROCESS:18beb9f0-7bcf-46ae-b4ff-bccac473d274/actions
Authorization: Bearer [token]
Content-Type: application/json
The Autenti system, just as the IVR in our "signature by telephone" analogy, will instruct your system of the options you have (an underlying assumption is that while your system might not be prepared to act in a particular role, the user might be perfectly able to understand what is requested him/her to do). So, if only your system knows that the user is expected to select an option, it can neatly present a list of options and a selection mechanism - and even a text only teletype-kind-of interface (today know as a chatbot :) ) is perfectly able to present such a challenge. If a new participant role is made available tomorrow, it will still be available to your users!
A challenge response is always a "403 Forbidden" response, with the body explicitly informing it is a challenge response, and one or more X-CHALLENGE headers containing the challenge description(s) - see 'Challenge response'. Multiple challenges, if returned in a single step should be interpreted as prerequisites jointly required to succeed - prerequisites for the process to reach its end).
A challenge response
HTTP/1.1 403 Forbidden
Date: Sun, 31 Jan 2021 12:56:12 GMT
Content-Type: application/json
X-CHALLENGE: ewoiY2xhc3NpZmllcnMiIDogWyAiQ0hBTExFTkdFX0NMQVNTSUZJRVItVU5JUVVFX1RZUEU6QUNUSU9OX1NFTEVDVElPTiIsCiJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIiBdLAoiYXR0cmlidXRlcyIgOiB7CiJvcHRpb25zIiA6IFsgewoiaWQiIDogIkFDVElPTi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfU0lHTkFUVVJFIiwKImRlc2NyaXB0aW9uIiA6ICJTaWduIiwKIm1ldGEiIDogbnVsbAp9LCB7CiJpZCIgOiAiQUNUSU9OLVVOSVFVRV9UWVBFOlNJR05BVFVSRV9SRUpFQ1RJT04iLAoiZGVzY3JpcHRpb24iIDogIlJlamVjdCIsCiJtZXRhIiA6IG51bGwKfSBdCn0KfQ
{
  "type" : "/challenge",
  "title" : "Challenge requested",
  "status" : 403,
  "instance" : "fdd454b7-6de8-4282-a326-0dacda71f19d"
}
The example above is an option selection challenge - in this particular example a request to choose one of possible actions (only actions available to given user in relation to this given document in its current state are actually presented, so if your are just a reviewer, there will be no "sign" action made available to choose!). The X-CHALLENGE headers contains a base64url encoded JSON representation of a challenge structure (see: https://app.swaggerhub.com/apis/Autenti.com/Autenti-Document-Process-API/v2-bespin#/Challenge)
In decoded form it is actually quite easy to interpret:
An option selection challenge
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "options" : [
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION",
          "description" : "Sign"
        },
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION",
          "description" : "Reject to sign"
        }
    ]
  }
}
All your application is required to do is to show this choice to a user. Once the user selects the action he/she wants (say: to sign!), the decision is encoded in a statement, called assertion (the statement asserts the decision was made). There are different types of assertions, just as there are different kinds of interaction needed to fulfill a challenge - but there is only few of them. Each assertion is created from the corresponding challenge, and the user input (actual input, a decision made, a consent expressed and so on …​).
Let’s look at the example of the assertion describing the fact the user wants to sign (has selected the "Sign" option out the ones made available to him):
An assertion of option selection
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "selectedIds" : ["EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION"]
  }
}
The mechanics of assertion creation in reaction to different types of challenges is described in greater detail in following sections, see: Generic handling of challenges based on user interaction type, but it s easy to observe the assertion refers to the challenge it satisfies with a unique challenge type classifier, and contains attributes describing the input (or any other result) it is to pass to the server.
Assertions are serialized into JSON as above, encoded with base64url and added to X-ASSERTION header of the next request in the process. So, the next request, to continue the process would be as below:
POST /document-processes/DOCUMENT_PROCESS:18beb9f0-7bcf-46ae-b4ff-bccac473d274/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0UtQ0xBU1NGSUVSLTpVTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiBbIkFDVElPTi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfU0lHTkFUVVJFIl0KICB9Cn0
The back-and-forth cycle of challenge→action/decision/input→assertion continues until the end goal is achieved (which returns the resulting event description) or an unrecoverable error is detected. That way processes of arbitrary complication can be divided to simple actions, one at a time, and the closed catalogue of interaction option allows to prepare generic ways to react to even previously unknown challenge.
It is worth mentioning at this point that the backend does not hold assertions, there is no "session" context. SO, after each step is performed, the set of assertions grows and is passed in its entirety to the server (unless the server instructs otherwise, to remove some of assertions - say invalid password - or asks to add one of its own to the set maintained by the client application.)

Why is it so complex?

You might be asking if a more traditional approach, with a specialized API for each of the actions that can be performed on a document, and a fixed schema would not be easier to implement. And you might be right, provided you look at the problem at a single point in time. For example, at the time of writing, there are two different providers of qualified signatures Autenti works with (SimplySign and Infocert). Each of them uses a different way of authorizing the signature request, each uses a different number of steps an application has to make to succeed.
But each of them can change those at any time. Additionally, Autenti can add new ways of interacting with a document (as we did in the past, implementing approvals and reviews). Also - new integrations will appear. So the situation today, and tomorrow, can be quite different.
Let’s assume we are to add a third provider of qualified signature. That one, instead of using one-time passwords sent via SMS (as Infocert does), or generated using some additional application (as SimplySign does), would depend on Google Authenticator. We could surely create another version of out signature API, with a set of new fields your application would need to fill and send to us to sign. But until you adapt your application would not be able to benefit from a new provider.
Even worse, if a new security mechanism was added to the system, for example expecting a user to identify himself using an identity broker, before being able to participate in the process - your application, without the ability to understand what is expected and how to add those new required fields (not even mentioning asking the user to do something extra), would be useless.
Autenti is growing fast, and we add features every month. It is neither practical, nor desirable, to make every connected application follow those changes immediately, update themselves and enforce the users to update their versions. Missing a new feature is one thing, but loosing access to your documents or not being able to sign this critical agreement when abroad, cause someone asked to do it in a way your application does not support - would be much worse …​
Therefore Autenti has designed an extensible system. If only your application can handle few basic actions (interactions), it will be able to support the new features, without any change. Surely, from time to time such an addition will result with a bit worse experience compared to a tailored integration, but at the same time no one would ever be left with no options to complete their tasks. It is worth the hassle!

Generic handling of challenges based on user interaction type

At the time of writing there are several tens of different challenges (and corresponding assertions) used in the system. Most of them require the user to perform some action, and some trigger automated processes.
It would be quite demanding for a new integration to code support for all of those different challenges from day one. And, as already noted, the list is ever changing, so an attempt would be futile anyway. Therefore all the challenges requested by the system are categorized (classified), so that uniform handling can be used for every challenge classified the same way. The most important classification dimension is by the required type of interaction needed to satisfy the challenge.
For example, if the user is expected to choose one of the available options, this can easily be handled generically, by describing the options to the user (by convention using the description attributes provided), and making the user choose one, then returning the selected option identifier as the selected one.
At the time of writing there are 7 types of requested interaction:
  • User interaction: INPUT
  • User interaction: SELECTION
  • User interaction: CONSENT
  • User interaction: NONE
  • User interaction: HTTP_REQUEST
  • User interaction: VIDEO - reserved for future use, not specified yet
  • User interaction: PHOTO - reserved for future use, not specified yet
User interaction: INPUT
The challenges that will need the user to enter some value, for example amount, or one time code from SMS. The value entered by user is sent back in "input" attribute of the assertion, as text.
Example user input based challenge and corresponding assertion: Get OTP from user, sent by Infocert in SMS
Example challenge requesting user input
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_PIN",
    "CHALLENGE_CLASSIFIER-RESTARTABILITY:RESTARTABLE",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:USER_INPUT"
  ],
  "attributes": {}
}
Example assertion with a value provided by the user
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_PIN" ],
  "attributes" : {
    "input" : "12345678"
  }
}
User interaction: SELECTION
The challenges that will need the user to choose from available options described in the challenge, for example choosing the provider of the signature to be used, or one of preferences. The value(s) entered by user is/are sent back in "selectedIds" attribute of the assertion, as an array with items equal "id" field of the option(s)) selected. The "mode" attribute controls whether one or multiple options can be selected (defaults to "single" if no value is provided)
Example user selection based challenge and corresponding assertion: Select Infocert Alias
Example selection challenge
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_ALIAS_SELECTION",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION"
  ],
  "attributes": {
    "mode" : "single",
    "options": [
      {
        "id": "INFOCERT_ALIAS:KT_48601123654",
        "description": "KT_48601123654"
      },
      {
        "id": "INFOCERT_ALIAS:KT_48871223654",
        "description": "KT_48871223654"
      }
    ]
  }
}
Example selection assertion
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_ALIAS_SELECTION"
  ],
  "attributes": {
    "selectedIds": [
      "INFOCERT_ALIAS:KT_48871223654"
    ]
  }
}
The assertions that will need the user to express consent to a statement presented to him/her. The value entered by user is sent back in "consentedIds" attribute of the assertion, as the collection of identifiers (id field values) of the consented statements.
Example user consent based challenge and corresponding assertion: Request the user’s consent to Infocert requested statements
Example consent challenge
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_CONSENT_INFOCERT",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:CONSENT"
  ],
  "attributes": {
    "consents": [
      {
        "id": "CONSENT-INFOCERT_SIGNATURE_CONSENT_ID:SIG1",
        "content": "I hereby agree to sign the presented document"
      },
      {
        "id": "CONSENT-INFOCERT_SIGNATURE_CONSENT_ID:SIG2",
        "content": "I confirm the content of the document is known to me"
      }
    ]
  }
}
Example consent assertion
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_CONSENT_INFOCERT"
  ],
  "attributes": {
    "consentedIds": [
      "CONSENT-INFOCERT_SIGNATURE_CONSENT_ID:SIG2",
      "CONSENT-INFOCERT_SIGNATURE_CONSENT_ID:SIG1"
    ]
  }
}
User interaction: NONE
Assertions stored in the client application as a result of instruction from the backend, or those that result from a challenge that can be satisfied automatically (say: IMEI number of the phone), may not include the user interaction classifier (or explicitly have it described as "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:NONE")
Example of assertion passed from the backend, that is to be returned back to the backend without bothering user: Store Infocert access token for later use
Example state modification challenge with no user interaction
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ASSERTION_STORE",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:NONE"
  ],
  "attributes": {
    "assertions": [
      "eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfT1JfQVNTRVJUSU9OX0NMQVNTXFw6VU5JUVVFX1RZUEU6SU5GT0NFUlRfQUNDRVNTX1RPS0VOIl0sImF0dHJpYnV0ZXMiOnsidmFsdWUiOiJzb21lYWNjZXNzdG9rZW52YWx1ZXRvYmV1c2VkdXNlbGF0ZXIifX0"
    ],
    "invalidations": [
      "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_ACCESS_TOKEN"
    ],
    "replacements": []
  }
}
User interaction: HTTP_REQUEST
There are situations when completion of given action cannot be handled via the API. There might be technical (typically: a provider whose systems do lend themselves to be operated via API), and legal reasons for such situation.
The most common situation is when the application connected to Autenti system was not audited by Autenti and Autenti’s partners to conform to the requirements of electronic signature regime (those include requirements of handling credentials needed to apply signatures, requirements of presenting the content of the document to sign, and many others). Such applications will be presented an option to complete their tasks using Autenti system, via a redirection to a web page (similar or identical to the user interface the user can access using their dedicated link).
Challenges with HTTP_REQUEST interaction type are described by a number of parameters:
  • http-request - a description of the request to make
    • method: any valid HTTP method name, for example GET or POST
    • uri: the URL to send the requ to
    • headers: an optional (multi-value) map of headers to add to the request
    • body: an optional body to be sent with the request
    • body-encoding: an encoding applied to the body (helps to avoid issues in escaping special characters in the JSON description). Optional, defaults to plain (literal), other values include base64 or base64 url. The body should be decoded before adding it to the request
  • http-request - an optional user interaction mode description, defaults to "browser" which requests opening the response to the request in a web browser (web view, tab, iframe etc.). Can be "headless" which implies there is no meaningful content to be presented to the user nor user interaction involved (reserved for future API calls description, for example for firewall traversal scenarios or sophisticated SSO).
Example HTTP
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:QUALIFIED_SIGNATURE_UI_REDIRECT",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:HTTP_REQUEST"
  ],
  "attributes": {
    "http-request" : {
      "method" : "POST",
      "uri" : "https://autenti.com/sign/1e7c1447-747d-4812-a5ca-89ddebbd41a4",
      "headers" : {
        "X-AUTH-TOKEN" : ["zB8SttFsNNmYwEOxtXAa"],
        "Content-Type" : ["x-www-form-urlencoded"]
      },
      "body" : "literal body to be sent",
      "body-encoding" : "plain"
    },
    "user-interaction" : "browser"
  }
}
Autenti reserves two custom headers (observe random string in the header to avoid potential header name conflict) that can be added to the request be the application executing the request, to support navigating back to the calling application after the action: * XX-YXV0ZW50aS5jb20-SUCCESS-REDIRECT-URL * XX-YXV0ZW50aS5jb20-ERROR-REDIRECT-URL Autenti systems which support those parameters (none at the time of writing) will honor the values provided and redirect (HTTP 3xx code) to the provided URLs , after successful, or failed completion of the sub-process initiated by given HTTP request. If only one of those parameters is given both success and errors.
Systems integrating with Autenti to describe a return path to the calling application. On mobile clients deep links enable the calling mobile application to be restored to the front in the right place and communication of the results shown.
Redirection is NOT guaranteed to happen.

Client side assertion store

The system is built upon assumption the system uses the client to store state for it. The state is just a set of assertions, just as those produced by user interaction. Assertions can be also added to state by explicit request of the server.
Request to store state
The request to store the assertions (or actually - request to modify the content of the state store) is sent to the client application in the form of special challenge (classified with "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ASSERTION_STORE")
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ASSERTION_STORE",
    "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:NONE"
  ],
  "attributes": {
    "assertions": [
      "eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfT1JfQVNTRVJUSU9OX0NMQVNTXFw6VU5JUVVFX1RZUEU6SU5GT0NFUlRfQUNDRVNTX1RPS0VOIl0sImF0dHJpYnV0ZXMiOnsidmFsdWUiOiJzb21lYWNjZXNzdG9rZW52YWx1ZXRvYmV1c2VkdXNlbGF0ZXIifX0"
    ],
    "invalidations": [
      "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:INFOCERT_ACCESS_TOKEN"
    ],
    "replacements": []
  }
}
Processing of challenges should be done in a strict order: 1. For any assertions classified with (all) the classifiers listed in "invalidations" - remove them from "scope" (if given - otherwise - remove from any scope/all scopes). 2. Add all the assertions listed in "assertions" (those are in stringified form identical to the one passed in X-ASSERTION header) to given "scope". if no "scope" given, assume CONTINUATION scope (continuation scope is a scope of a single continuous flow of actions leading to a result, such as signing a document).
Scopes define the validity of given set of assertions, in respect to a process of achieving some goal. Currently the scopes defined are as follows:
  1. REQUEST - use (send) in one, single request, the next one in process, an ephemeral assertion
  2. CONTINUATION - use (send) in all requests till the end of the logical process (say: signing). An application MAY maintain multiple separate CONTINUATION scopes, if multiple processes can be done in parallel (for example: acting on many documents in different tabs). As a rule, acting on the same document from multiple contexts in parallel SHOULD be avoided, and may lead to inability to finish one or all of those parallel processes.
  3. UNINTERRUPTED_SESSION - use as long as the user interaction with the system is uninterrupted (reserved for future elevated auth scenarios)
  4. TIMED - use for some limited time, specified in the attribute "expiration" (reserved for future scenarios)
  5. SESSION - use as long as the user is in session with the app (reserved for future elevated auth scenarios)
  6. INDEFINITE - store permanently (on disk), removed only on explicit request (see: "invalidations")
Replacements
  • (reserved for future use) mark the assertion so that if this assertion is sent, the system will not send assertions classified as described in the "replacements" (but will not remove those assertions from scopes, just ignore them if it decides to send givne assertion).
Support for replacements is optional, it is an optimisation mechanism meant to avoid sending excessive number of assertions if those can be jointly represented by another.

Restartable challenges

Process that resulted in a challenge, may be restartable. A user (or API client system) may request to start the process anew (restart). For example, if the user is requested to provide a code from SMS, but the SMS expired, or never reached the user, a request to restart the SMS challenge will result in the server sending a new SMS, and responding with a new challenge for SMS code.
All restartable challenges are classified using "CHALLENGE_CLASSIFIER-RESTARTABILITY:RESTARTABLE" classifier (will have other classifers - for sure UNIQUE_TYPE classifier, but one should depend on the restartable classifier deciding if the given challenge may be restarted, not bind to unique type).
Requesting restart of a step
Challenge can be requested to be restarted by the client application by sending a special assertion, classified with "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:CHALLENGE_RESTART". The attribute "challenge" of the assertion shall contain a stringified form of the challenge to restart (just as received in X-CHALLENGE header).
{
  "classifiers": [
    "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:CHALLENGE_RESTART"
  ],
  "attributes": {
    "challenge": "eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfT1JfQVNTRVJUSU9OX0NMQVNTXFw6VU5JUVVFX1RZUEU6U0lHTkFUVVJFX0lORk9DRVJUX1NNU19PVFBfQVVUSE9SSVpBVElPTiIsIkNIQUxMRU5HRV9PUl9BU1NFUlRJT05fQ0xBU1NcXDpSRVNUQVJUQUJJTElUWTpSRVNUQVJUQUJMRSIsIkNIQUxMRU5HRV9PUl9BU1NFUlRJT05fQ0xBU1NcXDpVU0VSX0lOVEVSQUNUSU9OX1RZUEU6VVNFUl9JTlBVVCJdLCJhdHRyaWJ1dGVzIjp7fX0"
  }
}

Challenges created as a result of a recoverable error

The processes, especially multi-step processes that require a longer time to complete are prone to errors, both inherent to the process (for example timeouts), and resulting from user errors such as mistype entries or forgotten passwords.
If the process detects an error that it can recover from by requesting to re-do an action or perform some other (for example: retype the password, send another SMS with a new code or ask to user to wait an hour) it raises a challenge describing such desired action. Such a challenge may include a description of the error that led to it, to assist and inform the user (for example: to inform provided credentials were not valid, and to double check them).
The API describes a convention-based way of describing the errors to the user in a challenge: an array of error description objects in the "errors" attribute. The error object contains a unique error identifier that can help when searching for support (allows the support to find the error and events leading to it in the logs) as well as a human readable description of the issue. The descriptions will be translated to supported languages (at the time of writing Polish and English), based on the Accept-Language header value of the request (or in English, if not given).

Integration scenarios & examples

Querying existing documents

The documents accessible to given user can be queried by API.
One way is by using a unique, known identifier of a document. Such identifier may be received in a notification, simply known to a user from any user interface, or otherwise recorded.
GET /api/document-processes/DOCUMENT_PROCESS:ac842283-afd4-4e26-9873-2bf35bd89b42
Authorization: Bearer [token]
Content-Type: application/json
An example document process representation
{
  "id": "DOCUMENT_PROCESS:ac842283-afd4-4e26-9873-2bf35bd89b42",
  "title": "Sailing boat rental agreement",
  "description": "Please review the terms and sign",
  "processLanguage": "en",
  "status": "PROCESSING",
  "parties": [
    {
      "party": {
        "id": "PARTY-PUBLIC_APPROVAL_PROCESS_ID:4060e833",
        "firstName": "Mark",
        "lastName": "Wazowski",
        "name": "Mark Wazowski",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "mark.wazowski@acme.com"
            }
          }
        ],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE",
            "party": {
              "name": "Acme Co.",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "898123432"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "President"
            }
          }
        ]
      },
      "role": "APPROVER",
      "participationStatus": "COMPLETED",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 1
          }
        }
      ],
      "currentUser": false,
      "participationEvents": [
        {
          "eventType": "APPROVAL",
          "timestamp": "2020-10-21T15:48:34.863Z"
        },
        {
          "eventType": "VIEWING",
          "timestamp": "2020-07-18T19:16:40.997Z"
        }
      ]
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:4060e833",
        "firstName": "John",
        "lastName": "Smith",
        "name": "John Smith",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "john.smith@acme.com"
            }
          }
        ],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:REPRESENTATIVE",
            "party": {
              "name": "Acme Co.",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "898123432"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Salesman"
            }
          }
        ]
      },
      "role": "SIGNER",
      "participationStatus": "COMPLETED",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 2
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        }
      ],
      "currentUser": true,
      "participationEvents": [
        {
          "eventType": "SIGNATURE",
          "timestamp": "2020-10-21T15:48:34.863Z"
        },
        {
          "eventType": "VIEWING",
          "timestamp": "2020-06-18T19:16:40.997Z"
        }
      ]
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:bdb551b2",
        "firstName": "Maurice",
        "lastName": "Chevallier",
        "name": "Maurice Chevaller",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "chevallier1981@gmail.com"
            }
          }
        ]
      },
      "role": "SIGNER",
      "participationStatus": "PENDING",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 3
          }
        }
      ],
      "currentUser": false
    },
    {
      "party": {
        "id": "PARTY-PUBLIC_SIGNING_PROCESS_ID:4060e833",
        "firstName": "John",
        "lastName": "Smith",
        "name": "John Smith",
        "contacts": [
          {
            "type": "CONTACT-TYPE:EMAIL",
            "attributes": {
              "email": "john.smith@acme.com"
            }
          }
        ]
      },
      "role": "SENDER",
      "participationStatus": "COMPLETED",
      "currentUser": true,
      "participationEvents": [
        {
          "eventType": "SUBMISSION",
          "timestamp": "2020-06-18T19:16:40.997Z"
        }
      ]
    }
  ],
  "contentElements": [
    {
      "id": "FILE-SOURCE_FILE:3cf4307e-63cc-4be9-b616-bd2b99d9778e",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "1",
      "modificationTime": null,
      "filePurpose": "SOURCE_FILE",
      "mimeType": "application/pdf"
    },
    {
      "id": "FILE-DTBS:ac842283-afd4-4e26-9873-2bf35bd89b42/DTBS",
      "filename": "SailCruiser-15-rental.pdf",
      "description": null,
      "version": "999",
      "modificationTime": null,
      "filePurpose": "PARTIALLY_SIGNED_CONTENT_FILE",
      "mimeType": "application/pdf"
    }
  ],
  "tags": [

  ],
  "flags": [
    "FLAG:VIEWED"
  ],
  "createdAt": "2020-06-18T19:16:40.997Z",
  "modifiedAt": "2020-10-21T15:48:34.863Z"
}
A list of documents can also be retrieved. The API supports filtering by creation and modification data, sorting by one of those dimensions in ascending and descending order, as well as pagination with limit and offset. Additionally parameter "status" filters documents by their lifecycle progress: status=DRAFT returns documents not sent yet, status=DOCUMENT_PROCESS returns documents sent (and in any stage of processign, including completed processes), status=EVERYTHING include both kinds, but limitations to offset parameter apply (see further in the section)
Long lists of documents can be requested either in a traditional, paginated, JSON representation, by adding the appriopriate Accept header (Accept: application/json):
GET /api/document-processes? limit=50 & offset=50 & modifiedAfter=2021-01-12T13:11:02.002Z
Authorization: Bearer [token]
Accept: application/json
Streamed responses are also supported, and benefit from the flow control mechanism (backpressure) if the client cannot meet the supply. As opposed to paginated response streams are potentially unbounded (while can be bounded if limit is explicitly provided). If no "status" query parameter is given, or status is equal to "EVERYTHING", the maximum offset that can be given is 256. This limitation is not in force if the status parameter is "DRAFT" or "DOCUMENT_PROCESS".
GET /api/document-processes? [limit=5000 & offset=500] & modifiedAfter=2021-01-12T13:11:02.002Z & status=DRAFT
Authorization: Bearer [token]
Accept: application/stream+json
An example streamed response in application/stream+json (shortened)
{ "id": "DOCUMENT_PROCESS:ac842283-afd4-4e26-9873-2bf35bd89b42", // omitted }
{ "id": "DOCUMENT_PROCESS:526803c2-ed2c-4427-9533-ce432639b2c8", // omitted }
{ "id": "DOCUMENT_PROCESS:7afaa96f-3d73-44e4-9551-af9a2014388c", // omitted }
{ "id": "DOCUMENT_PROCESS:e11928c1-ad4b-409d-bab2-2d03a5c49e51", // omitted }
{ "id": "DOCUMENT_PROCESS:7ce5ae9d-67e8-45cf-8c29-d98be9f9f6a1", // omitted }
...
{ "id": "DOCUMENT_PROCESS:756223d4-0933-44dd-be8b-3e27923092eb", // omitted }
{ "id": "DOCUMENT_PROCESS:d250707c-78db-4f8e-a9c9-7dc3f8e62954", // omitted }
{ "id": "DOCUMENT_PROCESS:bb842283-afd4-4e26-9873-f24421223333", // omitted }

Access constraints when accessing documents' list

A document itself, or any action on it may be constrained. A typical constraint will require user to perform additional identity verification, prove to know a password or be in control of some mobile number. Another group could be limitations to the channels that can access the document, or times (such as expiration). Action of any party can be also constrained, for example specific kind of signature can only be used to sign the document.
Most of constraints will result in a challenge when a constrained action is attempted.
Constraints to access to a document will result in a challenge when access is attempted directly using the document ID, but have to result in slightly different approach when a constrained document is listed by a search or list retrieval operation. Such document will appear on the list with only minimal set of data (such as title) and details of constraints that were applied resulting in the access limitation (thus informing the client system the document exists, and that there will be additional actions needed (easily discovered by triggering a challenge response on access attempt). Constraints are quite well described on such document, so the user can have either graphical or any other indication of what is expected (say a telephone with a lock to signal an SMS verification will be required to unlock such a document).
A catalogue of known constraints will be gradually documented in examples section of the Open API Specification of Autenti API. Any system integrating with Autenti needs to be prepared for new kinds of constraints to appear in the future, and MUST NOT react to them with an error (but may indicate its inability to aleviate such constraint unknown to it, as long as it avoids signalling it as an Autenti system failure).

Retrieving files and files' metadata

A document process can be associated with a number of files. As described already, files can have different purpose, and some of them may be provided by the user - the source files, composed into a single "data to be signed" (DTBS) object (and in the future other attachment types).
Information about the files associated with given process can be retrieved via the /document-process/{document-id}/files endpoint, or read from the "files" collection in the document details.
Retreiving a list of files of a document process
GET https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files
Accept: application/json
Authorization: Bearer [token]
Also, individual files can be also queried by their identifier:
Retrieving file metadata
GET https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files/FILE-SOURCE_FILE:3cf4307e-63cc-4be9-b616-bd2b99d9778e
Accept: application/json
Authorization: Bearer [token]
Last, but not least, the content of the file can be downloaded. A specific version may be requested by providing a standard "If-Match" header naming the version - if version changed (is no longer available) an error will be returned. Otherwise, the file content will be returned.
File download supports resuming, by the use of standard Range header.
Retrieving file metadata
GET https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files/FILE-SOURCE_FILE:3cf4307e-63cc-4be9-b616-bd2b99d9778e/content
Accept: */*
If-Match: 212431af2e7
Range: bytes=200-
Authorization: Bearer [token]

Creating & sending a document via API

Document process have two distinct stages - preparation, visible only to its creator (sender), when it remains in the draft status, and then processing. The progression from draft to the document in processing requires an explicit creator (sender) action, and will only succeed when certain expectations are met: there are source files added, at least one recipient named etc.
Until sending is attempted there is virtually no single element of the document, so a document with just an ID (and a title, but a title will be provided with placeholder value on creation, if none given) can exist in draft status.
So, the simplest way to create a document is a RESTful POST to the collection of documents. It can contain almost everything about the document (except for files), or nothing at all, as the only really required field at this stage is a title which would be provided with placeholder value.
POST https://api.autenti.com/api/v2/document-processes
Accept: application/json
Content-Type: application/json
Authorization: Bearer [token]
This will return a 200 OK message, if successful, and the most important element to note is the ID of the newly created draft. It is needed to operate on the document.
200 OK
Content-Type: application/json

{
  "id" : "DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf",
  "title": "Placeholder title",
  "processLanguage": "pl"
}
Document after creation can be manipulated with either PUT or PATCH to its address (PUT would overwrite whatever content there is, while PATCH changes only fields present in the request, leaving other intact).
PUT https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf
Accept: application/json
Content-Type: application/json
Authorization: Bearer [token]

{
  "title": "Boat rental agreement",
  "description": "A boat rental agreement, between Marcin Niegodziwy of Eveil Empire and SunSails Co.",
  "processLanguage": "pl",
  "parties": [
    {
      "party": {
        "firstName": "Marcin",
        "lastName": "Niegodziwy",
        "name": "Marcin Niegodziwy",
        "email": "marcin.niegodziwy@fake.autenti.com",
        "extIds": [],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:MEMBER",
            "party": {
              "name": "The Evil Empire",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "9979979979"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Emperor"
            }
          }
        ]
      },
      "role": "SIGNER",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        }
      ]
    }
  ],
  "tags": [
    {
      "id": "TAG:5f744c47223ddf2bd8133306"
    }
  ]
}
PATCH https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf
Accept: application/json
#Content-Type: application/json
Content-Type: application/merge-patch+json
version: 1
Authorization: Bearer [token]

{
  "title": "Agrrement of evil intent",
  "description": null,
  "tags": [
    {
      "id": "TAG:5f744c47223ddf2bd8133306"
    }
  ],
  "parties": [
    {
      "party": {
        "firstName": "Marcin",
        "lastName": "Niegodziwy",
        "name": "Marcin Niegodziwy",
        "email": "marcin.niegodziwy@fake.autenti.com",
        "extIds": [],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:MEMBER",
            "party": {
              "name": "Evil Empire",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "9979979979"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Emperor"
            }
          }
        ]
      },
      "role": "SIGNER",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:SIGNATURE_TYPE"
          ],
          "attributes": {
            "requiredClassifiers": [
              "SIGNATURE_PROVIDER-SIGNATURE_TYPE:BASIC"
            ]
          }
        },
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 3
          }
        }
      ]
    },
    {
      "party": {
        "firstName": "Marcin",
        "lastName": "Nikczemny",
        "name": "Marcin Nikczemny",
        "email": "marcin.nikczemny@fake.autenti.com",
        "extIds": [],
        "relationships": [
          {
            "type": "PARTY_RELATIONSHIP-TYPE:MEMBER",
            "party": {
              "name": "Evil Empire",
              "extIds": [
                {
                  "identificationSpace": "TAXID-PL-NIP",
                  "identifier": "9979979979"
                }
              ]
            },
            "attributes": {
              "relationshipDescription": "Vice-Emperor"
            }
          }
        ]
      },
      "role": "APPROVER",
      "constraints": [
        {
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PARTICIPATION_PRIORITY"
          ],
          "attributes": {
            "priority": 1
          }
        }
      ]
    },
    {
      "party": {
        "firstName": "Marcin",
        "lastName": "Szubrawy",
        "name": "Marcin Szubrawy",
        "email": "marcin.szubrawy@fake.autenti.com"
      },
      "role": "VIEWER",
      "constraints": [
        {
          "constrainedActions": [
            "CONSTRAINED_ACTION:VIEW"
          ],
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:DOCUMENT_ACCESS_OTP_AUTHORIZATION"
          ]
        },
        {
          "constrainedActions": [
            "CONSTRAINED_ACTION:VIEW"
          ],
          "classifiers": [
            "CONSTRAINT-UNIQUE_TYPE:PHONE_NUMBER"
          ],
          "attributes": {
            "phoneNumber": "48722722722"
          }
        }
      ]
    }
  ]
}
Collections of elements in the model (except for files) have their own manipulation methods on collection level (see Open API 3.0 specification for the detailed list). The example below shows adding a tag to a document (overwriting the list of tags), and removing a tag:
Replacing the list of tags on a document
PUT https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/tags
Accept: application/json
Content-Type: application/json
Content-Type: application/merge-patch+json
version: 1
Authorization: Bearer [token]

[
  {
    "id": "TAG:5f744c47223ddf2bd8133306"
  }
]
Deleting a tag from a document
DELETE https://api.autenti.com/api/v2/documents/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/tags
Accept: application/json
Authorization: Bearer [token]
Manipulating files is quite similar, the only differences are the fact files can be only operated on using their collection address (there is no option of adding a file or removing it by sending a POST, PATCH or PUT request to the document level)
Uploading a file
POST https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files
Content-Type: multipart/form-data; boundary=WebAppBoundary
Accept: application/json
Authorization: Bearer [token]

--WebAppBoundary
Content-Disposition: form-data; name="fileMeta"
Content-Type: application/json

{
"filename": "plan_zaglady.pdf",
"filePurpose": "SOURCE_FILE",
"mimeType": "application/pdf"
}
--WebAppBoundary--
Content-Disposition: form-data; name="file"
Content-Type: application/octet-stream

[some file content as stream of bytes]
--WebAppBoundary--
The JSON part of the request is optional, and as currently only SOURCE_FILE type files are uploadable this type is assumed. It is however reserved for future use with attachment files and other content not being subject of signature.
If missing, the file name would be taken from the Content-Disposition filename attribute: ontent-Disposition: form-data; filename="filename.pdf", and the purpose would be set to source file.
Files can onlyu be added (uploaded), or deleted, there is no replace operation possible. It is entirely valid to add two identical files, those woudl be joined in the docuemnt to be signed, so it is advised to have the files differentiable in case an operation failes with a heuristic result (timout etc.) to check if the file was uplaoded).
Files can be deleted as a collection (clreaing the collection):
Delete all files
DELETE https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files
Accept: application/json
Authorization: Bearer [token]
Delete a file
DELETE https://api.autenti.com/api/v2/document-processes/DOCUMENT_PROCESS:cc37ffda-dcce-43f0-8c5a-e1af0868dbdf/files/FILE:ca0c4ddf-0c73-4530-a2c1-4f7efdd85c1d
Accept: application/json
Authorization: Bearer [token]

Discovering tags available to user

The tags a given user can add to a document are dictated by permissions assigned by the superadmin. The list of available tags can be discovered by quering the /tags endpoint:
List tags available for a user
GET https://api.autenti.net/api/v2/tags
Authorization: Bearer [token]
Accept: application/json
The request shall return a (potentially empty) list of tags given user can use:
200 OK
Date: Wed, 10 Feb 2021 15:41:01 GMT
Content-Type: application/json

[
    {
      "id": "TAG:a1744c47235ff2bd81333333",
      "name": "Acme Co.",
      "type": "ORGANIZATION_IMPLICIT"
    },
    {
      "id": "TAG:5f744c47223ddf2bd8133306",
      "name": "Acme Co. - under NDA",
      "type": "ORGANIZATION_SHARED"
    }
]
Tags are classified with their type:
  • PRIVATE_TAG - reserved for future use by individual users, so that they can mark documents with #hashtags of their own
  • ORGANIZATION_SHARED - tags defined by the admisntrators to be used within the organisation. Can be used as a method of selecting documents to apply additional logic (for example: to apply preferences of communication, or to enable moderators access to the document).
  • ORGANIZATION_IMPLICIT - tags automatically added to all documents sent in context of given arginisation (when the sender is a representative of an organization). Cannot be explicitly added, will be added automatically upen sendign the document. Each organisational account defines a single tag of this type.

Sending a document

Once ready, the document can be sent, which will result in making it available to named participants of the process.
Sending a document is just an action on a document, available to a sender, if the document is in the draft state (and meets minimal requirements) - so is initiated the same way as any other actions with a simple POST that discovers possible actions. Sending the document would be on available actions list, in a form of an action selection challenge:
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b/actions
Authorization: Bearer [token]
Content-Type: application/json
403 FORBIDDEN
Content-Type: application/json
X-CHALLENGE: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIiwgIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkFDVElPTl9TRUxFQ1RJT04iIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgIm9wdGlvbnMiIDogWwogICAgICAgIHsKICAgICAgICAgICJpZCIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpFVkVOVF9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkRPQ1VNRU5UX1NFTlQiLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJTZW5kIgogICAgICAgIH0KICAgIF0KICB9Cn0

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"12051c21-7287-4727-b42f-8267c0733448"}
Decoded action selection challenge with a "Send" action
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "options" : [
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_SENT",
          "description" : "Send"
        }
    ]
  }
}
Selection of "Send" action encoded as assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "selectedIds" : ["EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_SENT"]
  }
}
The next request adds the encoded decision in X-ASSERTION header:
POST https://api.accept.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiBbIkVWRU5UX0NMQVNTSUZJRVItVU5JUVVFX1RZUEU6RE9DVU1FTlRfU0VOVCJdCiAgfQp9
As there are no other expectations before the document is sent, this shall result with a successful 200 OK response:
200 OK
Date: Wed, 10 Feb 2021 15:41:01 GMT
Content-Type: application/json

{"timestamp":"2021-02-10T15:37:37.311Z","id":"EVENT-AUTENTI:87c61861-DOCUMENT_SENT","eventType":"EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_SENT","classifiers":["EVENT_CLASSIFIER-PROCESS:CREATE"],"actor":{"id":"PARTY-PUBLIC_SENDER_PROCESS_ID:87c61861"},"object":{"id":"DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b","type":"EVENT_OBJECT-TYPE:DOCUMENT_PROCESS"},"attributes":{}}

Signing (approving, reviewing) a document

A person who is named a signer of document can request signing the document via the API. Similarly, approvers and reviewers can also act on the document in the respective role (the basic process is very similar). The scenario below illustrates a typical basic signature process.
For advanced qualified signature processes available to selected customers bound by bilateral agreements with Autenti - contact Autenti representative. Advice and requirements of qualified signature will be available and correctness of integration (as well fulfillment of legal obligations for qualified signature signing applications) asserted as part of an audit process by Autenti and/or its partners.
The process of signing starts, any other in the API, with a generic action initiation request:
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b/actions
Authorization: Bearer [token]
Content-Type: application/json
As the initial request did not contain information about desired action, a challenge response is returned:
403 FORBIDDEN
Content-Type: application/json
X-CHALLENGE: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIiwgIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkFDVElPTl9TRUxFQ1RJT04iIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgIm9wdGlvbnMiIDogWwogICAgICAgIHsKICAgICAgICAgICJpZCIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQVBQTElDQVRJT04iLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJTaWduIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIiA6ICJFVkVOVF9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOlNJR05BVFVSRV9SRUpFQ1RJT04iLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJSZWplY3QgdG8gc2lnbiIKICAgICAgICB9CiAgICBdCiAgfQp9

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"12051c21-7287-4727-b42f-8267c0733448"}
The challenge describes the options. Actions are described using a language of desired end result: a type of event generated by successful action. For a hypothetical signer the list would be:
Decoded action selection challenge
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "options" : [
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION",
          "description" : "Sign"
        },
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION",
          "description" : "Reject to sign"
        }
    ]
  }
}
A corresponding assertion confirming user decision to sign would look very much like the below snippet:
An example selection of rejection to sign action as decoded assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "selectedIds" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION"
  }
}
The next request adds the encoded decision in X-ASSERTION header:
POST https://api.accept.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:4ee133f5-b37f-4213-b6b6-f7e9a72eb80f/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQVBQTElDQVRJT04iCiAgfQp9
but there are more decisions and actions needed:
403 FORBIDDEN
Content-Type: application/json
X-CHALLENGE: eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpQUk9WSURFUl9TRUxFQ1RJT04iLCJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIl0sImF0dHJpYnV0ZXMiOnsib3B0aW9ucyI6W3siaWQiOiJTSUdOSU5HX01FVEhPRF9QUk9WSURFUjpBVVRFTlRJIiwiZGVzY3JpcHRpb24iOiJBdXRlbnRpIHNpZ25hdHVyZSIsIm1ldGEiOm51bGx9XX19
X-CHALLENGE: eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQ09OU0VOVCIsIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVTRVJfSU5URVJBQ1RJT05fVFlQRTpDT05TRU5UIl0sImF0dHJpYnV0ZXMiOnsiY29uc2VudHMiOlt7ImlkIjoiQ09OU0VOVC1DT05URU5UX01ENV9IRVg6M2IxNDcwNWM1MWJkNzE0OGY1OThmM2EyYWIwMzA0ZGIiLCJjb250ZW50IjoiT8Wbd2lhZGN6YW0sIMW8ZSB6bmFtIGkgYWtjZXB0dWrEmSB0cmXFm8SHIHcgdWRvc3TEmXBuaW9ueWNoIHBsaWthY2ggb3JheiBha2NlcHR1asSZIHBvc3Rhbm93aWVuaWEgW1JlZ3VsYW1pbnUgUGxhdGZvcm15IEF1dGVudGldKGh0dHBzOi8vYXV0ZW50aS5jb20vcmVndWxhbWlueSkuIn1dfX0

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"12051c21-7287-4727-b42f-8267c0733448"}
The response (when decoded) describes two challenges. Please observe selection challenge with just one option - it is allowed not to present such choice to the user, and just select the only option behind the scene, with an exception for action selection which MUST BE explicit, even if only one action is possible):
A signature provider selection challenge
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:PROVIDER_SELECTION", "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION" ],
  "attributes" : {
    "options" : [ {
      "id" : "SIGNING_METHOD_PROVIDER:AUTENTI",
      "description" : "Autenti signature",
      "meta" : null
    } ]
  }
}
A consent challenge in the signature process
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_CONSENT", "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:CONSENT" ],
  "attributes" : {
    "consents" : [ {
      "id" : "CONSENT-CONTENT_MD5_HEX:3b14705c51bd7148f598f3a2ab0304db",
      "content" : "Oświadczam, że znam i akceptuję treść w udostępnionych plikach oraz akceptuję postanowienia [Regulaminu Platformy Autenti](https://autenti.com/regulaminy)."
    } ]
  }
}
Please DO NOT embed the expectation for any specific challenge, or number ochallenges to be recieved in any particular step in your code - the code needs to react to the challenges as they appear). Several challenges returned in a single response are expected all to be satisfied, and can be handled in any order, also sending the resulting assertion to the backend after fullfilling each of them.
The challenges above, when fullfilled result in two assertions (before encoding):
A provider selection assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:PROVIDER_SELECTION" ],
  "attributes" : {
    "selectedIds" : ["SIGNING_METHOD_PROVIDER:AUTENTI"]
  }
}
A provider selection assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_CONSENT" ],
  "attributes" : {
    "consentedIds" : [ "CONSENT-CONTENT_MD5_HEX:3b14705c51bd7148f598f3a2ab0304db" ]
  }
}
Both shall be sent in the next request (and the previously created action selection assertion stating the intended action is signature - shall be sent, too!):
POST https://api.accept.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:4ee133f5-b37f-4213-b6b6-f7e9a72eb80f/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQVBQTElDQVRJT04iCiAgfQp9
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpQUk9WSURFUl9TRUxFQ1RJT04iIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgInNlbGVjdGVkSWRzIiA6IFsiU0lHTklOR19NRVRIT0RfUFJPVklERVI6QVVURU5USSJdCiAgfQp9
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQ09OU0VOVCIgXSwKICAiYXR0cmlidXRlcyIgOiB7CiAgICAiY29uc2VudGVkSWRzIiA6IFsgIkNPTlNFTlQtQ09OVEVOVF9NRDVfSEVYOjNiMTQ3MDVjNTFiZDcxNDhmNTk4ZjNhMmFiMDMwNGRiIiBdCiAgfQp9
As for basic signature this satisfies all required expectations and all decisions and selections have been made, the process succeeds with a success response (200 OK):
200 OK
Date: Wed, 10 Feb 2021 15:41:01 GMT
Content-Type: application/json

{"timestamp":"2021-02-10T15:37:37.311Z","id":"EVENT-AUTENTI:87c61861-SIGNATURE_APPLICATION","eventType":"EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION","classifiers":["EVENT_CLASSIFIER-PROCESS:SIGNATURE"],"actor":{"id":"PARTY-PUBLIC_SIGNING_PROCESS_ID:87c61861"},"object":{"id":"DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400","type":"EVENT_OBJECT-TYPE:DOCUMENT_PROCESS"},"attributes":{}}

Refusing to sign a document

A named signer can may explicitly refuse to sign a document. Such an actions terminates the document process, the process ends in "rejected" state. Rejecting a document is an audited decision, and requires to explain the motivation to reject. Rejecting a document may also require explict consent which confirms the user understands the consequences. The decision, after it is committed, is irrevocable (a user cannot change his/her mind).
Rejecting a document is a relatively simple, one or two step, process:
As with any action, an intention to act is expressed in the first step:
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b/actions
Authorization: Bearer [token]
Content-Type: application/json
As the initial request did not contain information about desired action, a challenge response is returned:
403 FORBIDDEN
Content-Type: application/json
X-CHALLENGE: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIiwgIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkFDVElPTl9TRUxFQ1RJT04iIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgIm9wdGlvbnMiIDogWwogICAgICAgIHsKICAgICAgICAgICJpZCIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQVBQTElDQVRJT04iLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJTaWduIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIiA6ICJFVkVOVF9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOlNJR05BVFVSRV9SRUpFQ1RJT04iLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJSZWplY3QgdG8gc2lnbiIKICAgICAgICB9CiAgICBdCiAgfQp9

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"12051c21-7287-4727-b42f-8267c0733448"}
The challenge describes the options. Actions are described using a language of desired end result: a type of event generated by successful action. For a hypothetical signer the list would be:
Decoded action selection challenge
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "options" : [
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION",
          "description" : "Sign"
        },
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION",
          "description" : "Reject to sign"
        }
    ]
  }
}
A corresponding assertion confirming user decision to reject signing would look very much like the below snippet:
An example selection of rejection to sign action as decoded assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "selectedIds" : ["EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION"]
  }
}
A request passing this assertion (the signature rejection request) will be similar to the one below (please observe Base64Url encoded assertion in the X-ASSERTION header):
A document withdrawal request
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiBbIkVWRU5UX0NMQVNTSUZJRVItVU5JUVVFX1RZUEU6U0lHTkFUVVJFX1JFSkVDVElPTiJdCiAgfQp9
As all action assertions selecting signature rejection actions are virtually identical, the code can skip the round trip resulting with a challenge and can send a request directly, if it can establish a signature rejection action is possible for given user.
Rejection may require consenting to several statements, so a consent challenge is to be expected in the next step. Also, a reason for rejection need to be provided.
403 FORBIDDEN
Date: Wed, 10 Feb 2021 15:35:49 GMT
Content-Type: application/json
X-CHALLENGE: eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfUkVKRUNUSU9OX0NPTlNFTlQiLCJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6Q09OU0VOVCJdLCJhdHRyaWJ1dGVzIjp7ImNvbnNlbnRzIjpbeyJpZCI6IkNPTlNFTlQtQ09OVEVOVF9NRDVfSEVYOjNiMTQ3MDVjNTFiZDcxNDhmNTk4ZjNhMmFiMDMwNGRiIiwiY29udGVudCI6Ik_Fm3dpYWRjemFtLCDFvGUgem5hbSBpIGFrY2VwdHVqxJkgdHJlxZvEhyB3IHVkb3N0xJlwbmlvbnljaCBwbGlrYWNoIG9yYXogYWtjZXB0dWrEmSBwb3N0YW5vd2llbmlhIFtSZWd1bGFtaW51IFBsYXRmb3JteSBBdXRlbnRpXShodHRwczovL2F1dGVudGkuY29tL3JlZ3VsYW1pbnkpLiJ9XX19
X-CHALLENGE: eyJjbGFzc2lmaWVycyI6WyJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfUkVKRUNUSU9OX1JFQVNPTiIsIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVTRVJfSU5URVJBQ1RJT05fVFlQRTpVU0VSX0lOUFVUIl0sImF0dHJpYnV0ZXMiOnt9fQ

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"95e66e84-36af-4a56-ace0-15dbec83f886"}
The response above contains two challenges:
The first one is a consent challenge.
An example consent challenge received as part of signature rejection process
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION_CONSENT", "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:CONSENT" ],
  "attributes" : {
    "consents" : [ {
      "id" : "CONSENT-CONTENT_MD5_HEX:3b14705c51bd7148f598f3a2ab0304db",
      "content" : "Oświadczam, że znam i akceptuję treść w udostępnionych plikach oraz akceptuję postanowienia [Regulaminu Platformy Autenti](https://autenti.com/regulaminy)."
    } ]
  }
}
Consent to the statement should be asserted in the form similar to the assertion below:
An example consent assertion prepared as part of signature rejection process
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION_CONSENT" ],
  "attributes" : {
    "consentedIds" : [ "CONSENT-CONTENT_MD5_HEX:3b14705c51bd7148f598f3a2ab0304db" ]
  }
}
Second challenge asks to provide a reason fro rejection, and is a user input challenge:
An example user input requesting challenge askign for rejection reason
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:USER_INPUT", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION_REASON" ],
  "attributes" : { }
}
The reason provided by the user is recorded in an assertion similar to the one below:
An example consent assertion prepared as part of signature rejection process
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION_REASON" ],
  "attributes" : {
    "userInput" : "The document is not as agreed before"
  }
}
Both the assertions are added in the Base64Url encoded form as X-ASSERTION headers. Also the action selection assertion created in previous step - which is still in scope, as the process continues - is added, so must be kept in the state storage of the client application,
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3QiIDogIkVWRU5UX0NMQVNTSUZJRVItVU5JUVVFX1RZUEU6U0lHTkFUVVJFX1JFSkVDVElPTiIKICB9Cn0
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfUkVKRUNUSU9OX0NPTlNFTlQiIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgImNvbnNlbnRzIiA6IFsgIkNPTlNFTlQtQ09OVEVOVF9NRDVfSEVYOjNiMTQ3MDVjNTFiZDcxNDhmNTk4ZjNhMmFiMDMwNGRiIiBdCiAgfQp9
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfUkVKRUNUSU9OX1JFQVNPTiIgXSwKICAiYXR0cmlidXRlcyIgOiB7CiAgICAidXNlcklucHV0IiA6ICJUaGUgZG9jdW1lbnQgaXMgbm90IGFzIGFncmVlZCBiZWZvcmUiCiAgfQp9
All required challenges have been satisfied at this moment, so the rejection process completes successfully, which is returned in 200 OK response:
200 OK
Date: Wed, 10 Feb 2021 15:37:37 GMT
Content-Type: application/json

{"timestamp":"2021-02-10T15:37:37.311Z","id":"EVENT-AUTENTI:87c61861-SIGNATURE_REJECTION","eventType":"EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION","classifiers":["EVENT_CLASSIFIER-PROCESS:SIGNATURE"],"actor":{"id":"PARTY-PUBLIC_SIGNING_PROCESS_ID:87c61861"},"object":{"id":"DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400","type":"EVENT_OBJECT-TYPE:DOCUMENT_PROCESS"},"attributes":{"comment":"The document is not as agreed before"}}

Withdrawing a document before process completion

A sender (and in case of documents with specific company tags, a configured moderator of documents marked with given tag) can withdraw a document as long as the process was not completed (not all of required participants took part). Withdrawing a document makes it inactive, and it is its final state (it cannot be signed, one cannot re-activate it, too).
Withdrawing a document is a simple single step process:
As with any action, an intention
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:21c3a201-e3ea-4fbd-b850-2f0b8246ac2b/actions
Authorization: Bearer [token]
Content-Type: application/json
As the initial request did not contain information about desired action, a challenge response is returned:
403 FORBIDDEN
Content-Type: application/json
X-CHALLENGE: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VU0VSX0lOVEVSQUNUSU9OX1RZUEU6U0VMRUNUSU9OIiwgIkNIQUxMRU5HRV9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkFDVElPTl9TRUxFQ1RJT04iIF0sCiAgImF0dHJpYnV0ZXMiIDogewogICAgIm9wdGlvbnMiIDogWwogICAgICAgIHsKICAgICAgICAgICJpZCIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfQVBQTElDQVRJT04iLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJTaWduIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIiA6ICJFVkVOVF9DTEFTU0lGSUVSLVVOSVFVRV9UWVBFOkRPQ1VNRU5UX1dJVEhEUkFXQUwiLAogICAgICAgICAgImRlc2NyaXB0aW9uIiA6ICJXaXRoZHJhdyBkb2N1bWVudCIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJpZCIgOiAiRVZFTlRfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpTSUdOQVRVUkVfUkVKRUNUSU9OIiwKICAgICAgICAgICJkZXNjcmlwdGlvbiIgOiAiUmVqZWN0IHRvIHNpZ24iCiAgICAgICAgfQogICAgXQogIH0KfQ

{"type":"/challenge","title":"Challenge requested","status":403,"detail":"Request to perform challenges described","instance":"12051c21-7287-4727-b42f-8267c0733448"}
The challenge describes the options. Actions are described using a language of desired end result: a type of event generated by successful action. For a hypothetical sender, who is also a signer of the document, the list would be:
Decoded action selection challenge
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-USER_INTERACTION_TYPE:SELECTION", "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "options" : [
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_APPLICATION",
          "description" : "Sign"
        },
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:SIGNATURE_REJECTION",
          "description" : "Reject to sign"
        },
        {
          "id" : "EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_WITHDRAWAL",
          "description" : "Withdraw document"
        }
    ]
  }
}
Withdrawing requires the client application to create an assertion confirming the user intention (selection) to withdraw the document: In decoded form it would look like the below:
An example selection of document witdrawal action as decoded assertion
{
  "classifiers" : [ "CHALLENGE_CLASSIFIER-UNIQUE_TYPE:ACTION_SELECTION" ],
  "attributes" : {
    "selectedIds" : ["EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_WITHDRAWAL"]
} }
A request passing this assertion (the withdrawal request) will be similar to the one below (please observe Base64Url encoded assertion in the X-ASSERTION header):
A document withdrawal request
POST https://api.autenti.net/api/v2/document-processes/DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400/actions
Authorization: Bearer [token]
Content-Type: application/json
X-ASSERTION: ewogICJjbGFzc2lmaWVycyIgOiBbICJDSEFMTEVOR0VfQ0xBU1NJRklFUi1VTklRVUVfVFlQRTpBQ1RJT05fU0VMRUNUSU9OIiBdLAogICJhdHRyaWJ1dGVzIiA6IHsKICAgICJzZWxlY3RlZElkcyIgOiBbIkVWRU5UX0NMQVNTSUZJRVItVU5JUVVFX1RZUEU6RE9DVU1FTlRfV0lUSERSQVdBTCJdCiAgfQp9
As all action assertions selecting withdrawal actions are virtually identical, the code can skip the round trip resulting with a challenge and can send a request directly, if it can establish a withdrawal action is possible for given user.
Withdrawal of the document has not more prerequisites, thus the request shall succeed and return 200 OK response:
200 OK
Date: Wed, 10 Feb 2021 15:37:37 GMT
Content-Type: application/json

{
  "timestamp": "2021-02-10T15:37:37.311Z",
  "id": "EVENT-AUTENTI:87c61861-DOCUMENT_WITHDRAWAL",
  "eventType": "EVENT_CLASSIFIER-UNIQUE_TYPE:DOCUMENT_WITHDRAWAL",
  "actor": {
    "id": "PARTY-PUBLIC_SENDER_ID:87c61861"
  },
  "object": {
    "id": "DOCUMENT_PROCESS:b03be081-fd72-48f3-ae52-287b8045e400",
    "type": "EVENT_OBJECT-TYPE:DOCUMENT_PROCESS"
  },
  "attributes": {}
}