API information

Integrating S1SEVEN services within your server application, such as a SAP module, an automated delivery note service, or any other application managing quality certificates, is accomplished with the S1SEVEN REST API and optionally our Async API.

General information

Policies

S1SEVEN APIs are classified into either production or staging APIs. A production API is one that has been made generally available for public use and is stable. A staging API is one that is still in development or is for internal or limited use and whose stability cannot be guaranteed. Staging APIs may be removed or modified at any time without advance notice. The following policies apply to production APIs only.

Deprecation Policy

The current version of production-level APIs will happen once we release v2. When a new version of APIs is made generally available (not beta), the older version will be deprecated and will cease to function after six months. Once an API is removed, any request to it will result in a 404 error.

Breaking Change Policy

Changes that do not break an API, such as adding a new attribute can be made at any time. Changes that break a production level API such as removing attributes or making major changes to the API’s behavior will only be done with advance notice of X days. However, there may be rare occasions where we are forced to make breaking changes without advance notice due to legal, performance, or security reasons.

REST API

Swagger

All endpoints documented here will link to a Swagger UI hosted on our staging webservices allowing you to try the API with the closest conditions from production systems. For convenience, a Swagger UI aggregating all endpoints is available here.

  1. On the top left, select the server address matching the address of the Swagger you are currently browsing.

  2. On the top left, click Authorize button. Once logged in or if you use a long lived access token, fill the bearer field with your access token.

Rate Limit

The maximum number of REST API calls / client / minute is 10. Some endpoints might be subject to different rules, the value for each endpoint is documented in our API specifications.

Response headers

The status of the rate limit for a given endpoint can be found under the response headers:

  • X-RateLimit-Limit: the number of requests allowed for a given time span
  • X-RateLimit-Remaining: the number of remaining requests before reset
  • X-RateLimit-Reset : the nearest expiry time of the rate limiting in seconds

When the HTTP response contains the 429 status code (meaning that the rate limit was crossed), the headers should contain the Retry-After property, which contains the nearest expiry time (in seconds) of the rate limiting.

Requests

The API access pattern for all S1SEVEN REST endpoints is:

https://<s1seven_service_subdomain>.<s1seven_domain>/api/<service_resources>

or

https://<s1seven_proxy>.<s1seven_domain>/api/<service_resources>

The expected value for <s1seven_service> is the name of the service, such as user-service, km-service, certificate-service, pipe-service.

The list of valid resources and actions per service :
  "user-service" : {
    "users": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one", "confirm", "reset"]
    },
    "user_onboarding": {
      "actions": ["read_one"]
    },
    "companies": {
      "actions": ["read_one", "read_many", "validate_one", "create_one", "update_one", "delete_one", "confirm"]
    },
    "applications": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one"]
    },
    "applications_secrets": {
      "actions": ["rotate"]
    },
    "tokens": {
      "actions": ["create_one"]
    },
  },
  "km-service" : {
    "cointypes": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one"]
    },
    "nodes": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one"]
    },
    "wallets": {
      "actions": ["read_one", "create_one", "update_one", "delete_one"]
    },
    "identities": {
      "actions": ["read_one", "read_many", "create_one"]
    },
    "transactions": {
      "actions": ["read_one", "read_many", "partial_sign", "sign", "send"]
    }
  },
  "certificate-service" : {
    "certificates": {
      "actions": ["read_one", "create_one", "validate_one", "render_one", "notarize_one"]
    }
  },
  "pipe-service" : {
    "hooks": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one"]
    },
    "events": {
      "actions": ["read_one", "read_many", "update_one", "retry_one"]
    },
    "mailhooks": {
      "actions": ["read_one", "read_many", "create_one", "update_one", "delete_one"]
    },
    "mails": {
      "actions": ["read_one", "read_many", "update_one", "retry_one"]
    }
  },

API version

To access a specific API version use the x-version header, if undefined it will default to version 1 of the API.

curl --request POST \
  --url https://<api-endpoint> \
  --header 'content-type: application/json' \
  --header 'x-version: <major-version>'

Example

To show how to access resources, let's take the users resource from user-service as an example, located under the development subdomain s1seven.dev :

  • https://user.s1seven.dev/api/users
  • https://app.s1seven.dev/api/users/

Error Handling

Responses are formatted in the standard REST format, with a statusCode field showing an error code and a message field with a text description of the error. The possible error codes are described with each API endpoint.

For example, here is an example response for a failed signup request:

POST https://<s1seven-proxy>/api/users

{
  "statusCode": 400,
  "path": "/user",
  "method": "POST",
  "timestamp": "2021-06-10T14:40:52.602Z",
  "message": "Invalid credentials provided",
  "name": "BadRequestException",
  "details": ["invalid params"]
}

TIP

You can find the detailed schema in ErrorResponseDto in the OpenAPI specifications.

Common requests

Register user

  1. A new user can be registered using the create user endpoint.
  2. If you need to resend the verification email, use verify email endpoint.
  3. Once you confirmed the user creation, you can login via the Web UI.
  4. Retrieve user information with me endpoint

Register a company

  1. Login via the UI
  2. A new company can be registered using the create company endpoint.
  3. Once created you can get the list of the user's companies with the me endpoint.

Find own user

To fetch information about the user and companies attached to that account, the find user endpoint can be used. The user id is deducted from the JWT token provided in the header.

curl --request GET \
  --url https://<api-gateway>/api/users/me \
  --header 'content-type: application/json' \
  --header 'authorization: Bearer <jwt>'

Authentication

Most endpoints require authenticated calls to submit a request to the S1SEVEN servers. The API reference for each endpoint specifies the types of authentication needed to access the endpoint.

S1SEVEN uses username/password and access tokens to add a layer of security to the API requests from users.

Username and Password

To login with your user's credentials (email and password) you should use our web UI at https://app.s1seven.<s1seven_domain>, you will be redirected to https://auth0.s1seven.<s1seven_domain>/u/login where you can enter your credentials.

TIP

You can then retrieve the access token by accessing automate -> constants in our UI.

The access token must be added to the authorization header (as a bearer token) to every REST call.

WARNING

The access token is valid for 1 day.

Access Token Usage

Once you have an access token, you can call endpoints using it, such as:

curl --request GET \
--url http://<api-gateway>/api/companies/<company-id> \
--header 'authorization: Bearer <jwt>'

The header field has the format:

--header 'authorization: Bearer <token>'

M2M access token

Create

TIP

The machine to machine access token is restricted to a company resources and a mode.

WARNING

Up to 6 applications can be registered for a given company and one token can be regenerated / day / application.

For applications or scripts that require automated access to our API, a M2M access token can be created by following the given flow

  1. calling the create application operation and setting :
  • the company id in company header,
  • the JWT in authorization header,
  • the mode in the body,
  • the description in the body,
  • the scopes (which actions on which resource) that this application will grant access to, in the body

The returned application contains a clientId and clientSecret that can be used to generate an access token.

curl --request POST \
 --url https://<api-gateway>/api/applications \
 --header 'content-type: application/json' \
 --header 'company: <company-id>' \
 --header 'authorization: Bearer <jwt>' \
 --data '{
   "description": "test application",
   "mode": <test or live>,
   "scopes": {
      "companies": {
        "actions": ["read_one"]
      }
    }
  }'
  1. calling the create token operation and setting :
  • the clientId in the body
  • the clientSecret in the body

The returned JWT (accessToken property) must be added to the authorization header (as a bearer token) for every REST call.

curl --request POST \
 --url https://<api-gateway>/api/tokens \
 --header 'content-type: application/json' \
 --data '{
   "clientId": <application_clientId>,
   "clientSecret": <application_clientSecret>,
  }'
Example Scopes
{
  "cointypes": {
    "actions": ["read_one", "read_many"]
  },
  "nodes": {
    "actions": ["read_one", "read_many"]
  },
  "wallet": {
    "actions": ["read_one"]
  },
  "identities": {
    "actions": ["read_one", "read_many"]
  },
  "transactions": {
    "actions": ["sign", "send", "read_one"]
  },
  "companies": {
    "actions": ["read_one", "update_one", "validate_one"]
  },
  "certificates": {
    "actions": ["read_one", "validate_one", "notarize_one"]
  },
  "hooks": {
    "actions": ["create_one", "read_one", "read_many"]
  },
  "events": {
    "actions": ["read_one", "read_many"]
  },
  "mailhooks": {
    "actions": ["create_one", "read_one", "read_many"]
  },
  "mails": {
    "actions": ["read_one", "read_many"]
  }
}

TIP

For a complete list of available scopes, refer to CompanyTokenScopesDto in the OpenAPI documentation.

WARNING

The client id and client secret should be stored safely and the generated access token is available for 1 day.

Rotate credentials

It might be a good idea to rotate the credentials of your application periodically, depending on the level of the security required. Rotating an application clientSecret will invalidate the current access token.

  1. calling the rotate application secret operation and setting :
  • the application id in URL path parameter,
  • the company id in company header,
  • the JWT in authorization header,

The returned application contains the current clientId and the updated clientSecret.

curl --request POST \
 --url https://<api-gateway>/api/applications/<application-id>/rotate-secret \
 --header 'content-type: application/json' \
 --header 'company: <company-id>' \
 --header 'authorization: Bearer <jwt>' \
 --data '{}'

Async API

We provide a read-only (subscribe only) Async API that allows you to subscribe to events dispatched by our application. To connect to our broker use the URL patterns :

  • for MQTT : mqtts://broker.<s1seven_domain>:8883
  • for Websocket : wss://broker.<s1seven_domain>/ws/mqtt

Events

The events are sent to the owner of the resources, as MQTT messages (always) and Webhooks requests (when webhooks have been registered).

  1. For MQTT messages, the subscription patterns look like :
  • user/<user_id>/<mode>/<resource>/<action>
  • company/<company_id>/<mode>/<resource>/<action>
The list of available resources and actions that produce events :
{
  "companies": {
    "actions": ["update_one", "delete_one"]
  },
  "applications": {
    "actions": ["create_one", "update_one", "delete_one"]
  },
  "wallets": {
    "actions": ["create_one", "update_one", "delete_one"]
  },
  "identities": {
    "actions": ["create_one", "update_one"]
  },
  "transactions": {
    "actions": ["sign", "send"]
  },
  "certificates": {
    "actions": ["notarize_one", "receive_one"]
  },
  "hooks": {
    "actions": ["create_one", "update_one", "delete_one"]
  },
  "mail_hooks": {
    "actions": ["create_one", "update_one", "delete_one"]
  }
}

Authentication

In order to connect to the broker, the client needs to be authenticated with a valid access token (JWT).

  1. When connecting as a user,

    • the user id should be used with the vhost using the pattern <vhost>:<user_id> as username
    • the refresh token can be used as password and the entityType must be user
    • the clientId should follow the pattern user_<user_id>_*
  2. When connecting as a company,

    • the company id should be used with the vhost using the pattern <vhost>:<company_id> as username
    • an access token can be used as password and the entityType must be company
    • the clientId should follow the pattern company_<company_id>_*

WARNING

You must ask S1SEVEN for the vhost, it is not yet provided publicly. Without the vhost, you will not be able to connect.

Authorization

In order to subscribe to events, the client needs to be authorized with a valid access token, containing the appropriate scopes.

  1. When subscribing as a user,

    • the topic should start with user/<user_id>/
    • all possible subscriptions can be consumed
  2. When subscribing as a company,

    • the topic should start with company/<company_id>/
    • subscription topic needs to match the authorized scopes from the application / M2M access token.

For example to subscribe to company/<company_id>/live/certificates/notarize_one, the access token scopes should at least contain :

...
"certificates": {
  "actions": ["notarize_one"]
}
...
Node.js MQTT / Websocket client example
const mqtt = require('mqtt');

const entityType = 'company';
const entityId = `company_id`;
const vhost = '';
const mode = 'live';
const resource = 'certificates';
const action = 'notarize_one';

const username = vhost ? `${vhost}:${entityId}` : entityId;
const password = `company_access_token_jwt`;
const clientId = `${entityType}_${entityId}_test_123456789`;

const topic = `${entityType}/${entityId}/${mode}/${resource}/${action}`;

const url = 'mqtts://broker.s1seven.dev:8883';
// const url = 'wss://broker.s1seven.dev/ws/mqtt';

const client = mqtt.connect(url, {
  clientId,
  username,
  password,
  // allow to retrieve persisted messages published at reconnection time for a given clientId
  clean: false,
});

client.once('error', (error) => {
  console.error(error);
  process.exit(1);
});

client.on('message', (topic, payload) => {
  // handle incoming events
  console.log(" [x] %s: '%s'", topic, payload.toString());
});

client.subscribe(topic, { qos: 1 });

client.on('connect', () => {
  console.log('connected');
});

Persistence

When using QoS = 1 and stateful connections (clean = false), messages will be persisted for 30 minutes.

© 2023 S1SEVEN GmbH