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 has been made generally available for public use and is stable. A staging API 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.
On the top left, select the server address matching the address of the Swagger you are currently browsing.
On the top left, click
Authorize
button. Once logged in or if you use a long lived access token, fill thebearer
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 spanX-RateLimit-Remaining
: the number of remaining requests before resetX-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 complete schema in ErrorResponseDto
in the OpenAPI specifications.
Common requests
Register user
- A new user can be registered using the create user endpoint.
- If you need to resend the verification email, use verify email endpoint.
- Once you confirmed the user creation, you can login via the Web UI.
- Retrieve user information with me endpoint
Register a company
- Login via the UI
- A new company can be registered using the create company endpoint.
- 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
- 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"]
}
}
}'
- 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.
- 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 '{}'
Authorization
After creating a user and registering a first company, the company will need to be verified by our team so that you can access the complete API. This is to ensure that the company is real (use a correct VAT ID) and that the user is not a bot. As long as the company is not verified, you will be able to access all the endpoints but you will get a 403
error code for the read and write operations on the following live
resources :
- applications
- wallets
- identities
- transactions
Also, certificate notarization will be forbidden in live
mode.
After the company is verified, the user will need to enable at least one MFA method to be able to access the live
resources. The easiest way to do this is to use the UI and follow the instructions, you can also use our API to register a TOTP application and generate a recovery code
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).
- For MQTT messages, the subscription patterns look like :
user/<user_id>/<mode_or_wildcard>/<resource>/<action>
company/<company_id>/<mode_or_wildcard>/<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).
When connecting as a user,
- the user id should be used with the vhost using the pattern
<vhost>:<user_id>
asusername
- the access token should be used as
password
- the user id should be used with the vhost using the pattern
When connecting as a company,
- the company id should be used with the vhost using the pattern
<vhost>:<company_id>
asusername
- an M2M access token should be used as
password
- the company id should be used with the vhost using the pattern
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.
When subscribing as a user,
- the topic should start with
user/<user_id>/
- all possible subscriptions can be consumed
- the topic should start with
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.
- the topic should start with
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.