Logo
Sign in
  • {[{category.name}]}

    • {[{section.name}]}
      • {[{article.title}]}

Seamless API

  1. Seamless
  2. Technical insights
  3. Developers
 
 
  • Introduction
  • Authentication
  • Requests
  • Responses
  • Organization Units
  • Available Workspace Types
  • Workspaces

 

Introduction

Seamless is a fully hosted solution to manage workspaces. We provide a REST API built on pragmatic RESTful design principles.

Our API uses resource-oriented URLs that leverage built in features of HTTP, like authentication, verbs and response codes. All request and response bodies are JSON encoded, including error responses. Any off-the-shelf HTTP client can be used to communicate with the API.

We believe an API is a user interface for a developer - accordingly, we've made sure our API can be easily explored from the browser!

Authentication

Requests to the API are authenticated using access tokens.

To get an access token, install the API app from the apps tab of your help desk settings. Each instance of the API app has it's own access token.

Once you have an access token, it can be provided to the API as a basic token:

 curl -H 'Authorization: Basic token' https://api.seamlesswork.com/api

 

Requests

Server: api.seamlesswork.com

Route prefix: /api

Base url: {tenantName}

tenantName - parameter that determines SharePoint tenant of the Customer

HTTPS

All requests to the API must be sent over HTTPS. Any requests over plain HTTP will fail.

JSON Bodies

All POST, PUT requests are JSON encoded and must have content type of application/json, or the API will return a 415 Unsupported Media Type status code.

$ curl  https://api.seamlesswork.com/api/ \
-X PATCH \
-H 'Content-Type: application/json' \
-d '{"first_name":"John"}'

 

HTTP Verbs

We use standard HTTP verbs to indicate intent of a request:

  • GET - To retrieve a resource or a collection of resources
  • POST - To create a resource
  • PUT - To set a resource
  • OPTIONS - To find out which request methods a server supports for the target resource

Limited HTTP Clients

If you are using an HTTP client that doesn't support PUT, or OPTIONS requests, send a POST request with an X-HTTP-Method-Override header specifying the desired verb.

$ curl https://api.seamlesswork.com/api/ \
-X POST \
-H "X-HTTP-Method-Override: PUT"

 

Responses

All response bodies are JSON encoded.

A single resource is represented as a JSON object:

{
  "field1": "value",
  "field2": true,
  "field3": [],
  "field4": 1
}

 

A collection of resources is represented as a JSON array of objects:

[
  {
    "field1": "value",
    "field2": true,
    "field3": [],
    "field4": 1
  },
  {
    "field1": "another value",
    "field2": false,
    "field3": [],
    "field4": 1
  }
]

 

Timestamps are in UTC and formatted as ISO8601.

Unset fields will be represented as a null instead of not being present. If the field is an array, it will be represented as an empty array - ie [].

HTTP Status Codes

We use HTTP status codes to indicate success or failure of a request.

Success codes:

  • 200 OK - Request succeeded. Response included
  • 201 Created - Resource created. URL to new resource in Location header
  • 204 No Content - Request succeeded, but no response body

Error codes:

  • 400 Bad Request - Could not parse request
  • 401 Unauthorized - No authentication credentials provided or authentication failed
  • 403 Forbidden - Authenticated user does not have access
  • 404 Not Found - Resource not found
  • 415 Unsupported Media Type - POST/PUT request occurred without a application/json content type
  • 422 Unprocessable Entity - A request to modify or create a resource failed due to a validation error
  • 429 Too Many Requests - Request rejected due to rate limiting
  • 500, 501, 502, 503, etc - An internal server error occurred

Errors

All 400 series errors (400, 401, 403, etc) will be returned with a JSON object in the body and a application/json content type.

{
"Message": "Not Found"
}

500 series error codes (500, 501, 502, etc) do not return JSON bodies.

Validation Errors

In case of validation errors on a POST/PUT request, a 422 Unprocessable Entity status code will be returned. The JSON response body will include validation error messages.

{
"Message": "Tenant name must be provided."
}

 

Rate Limit

Rate limits determine how frequently you can call a particular endpoint.

Use the HTTP headers in order to understand where the application is at for a given rate limit, on the method that was just utilized.

  • x-rate-limit-limit: the rate limit ceiling for that given endpoint
  • x-rate-limit-remaining: the number of requests left
  • x-rate-limit-reset: the remaining window before the rate limit resets, in UTC epoch seconds

Number of request is limited to 100 requests per minute.

 

Organization Units

Each customer can have multiple smaller organization units that define closed work scope. Customer must have at least one (default) organization unit.

Endpoint serves to get the list of all organization units of the given tenant. It's a helping endpoint that is needed for proper creation of a workspace.

Field Type Notes
Id guid  
Name string Name of organization unit. Can be null.
ShortName string Short name assigned to organization unit. Can be null.
Logo string Assigned logo url. Can be null.

 

Listing organization units

GET /organizationUnits

 
Sample Request for organization units:

GET api/tenantname/organizationUnits
200 OK
Content-Type: application/json
[
  {
    "Id": "E555522C-6856-4B50-BC00-3D5C17129077",
    "Name": "Star Unit",
    "ShortName": "SU",
    "Logo": "https://amw-sml.azureedge.net/dev/assets/images/Logo.png"
  },
  {
    "Id": "731F7ACC-A9E6-498D-B8A5-0D4F4BD39272",
    "Name": "Butterfly",
    "ShortName": "BU",
    "Logo": "https://amw-sml.azureedge.net/dev/assets/images/LogoBU.png"
  }
]

 

Getting a single organization unit

GET /organizationUnits/{organizationUnitId} 

Sample Request:

GET  api/tenantname/organizationUnits/E3A4F5E7-30F1-43DB-AB5A-9153BA6CE9CE
200 OK
Content-Type: application/json
{
  "Id": "E3A4F5E7-30F1-43DB-AB5A-9153BA6CE9CE",
  "Name": "Perfect Unit",
  "ShortName": "PU",
  "Logo": "https://amw-sml.azureedge.net/dev/assets/images/Logo.png"
}

 

Available Workspace Types

Each organization unit has a list of available workspace types. Workspace type defines schema properties of a given workspace and its available tools. This endpoint provides a list of available workspace types for the given organization unit id.

GET /organizationUnits/{organizationUnitId}/availableWsTypes

 

Field Type Notes
Id guid  
Name string Description.
CreationMode int One of: Manual(0), Automated(1) or Both(2)
IsActive boolean Determines if workspace type is active and can be provisioned
SchemaDefinition string Schema which will be included in workspace type.
WorkspaceIdGenerator object Contains information about WorkspaceIdGenerator type. One of: None(0),PrefixWithId(1),Full(2), PrefixWithName(3)
ProvisioningType int Defines if SharePoint site collection or Microsoft Teams room will be created. One of: SharePoint(0),Teams(1)

None(0): prefix should not be set.PrefixWithId(1): prefix should be the part of WorkspaceId.Full(2): prefix should be the part of automatically generated WorkspaceId.PrefixWithName(3): prefix should be the part of automatically generated WorkspaceId same as alph numerics from Workspace Name.

For more information check the endpoint for Creating Workspace.


Sample Request for available workspace types:

GET api/tenantname/organizationUnits/E3A4F5E7-30F1-43DB-AB5A-9153BA6CE9CE/availableWsTypes
200 OK
Content-Type: application/json
[
  {
    "Id": "3B66DCCA-98AF-458A-AE36-A67BF199AC07",
    "Name": "Star Unit",
    "CreationMode": 1,
    "IsActive": "0",
    "SchemaDefinition": "[{\"FieldName\":\"StartDate\",\"FieldType\":\"datetime\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null},
       {\"FieldName\":\"EndDate\",\"FieldType\":\"datetime\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null},
       {\"FieldName\":\"Customer\",\"FieldType\":\"string\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null},
       {\"FieldName\":\"Description\",\"FieldType\":\"string\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null}]"
    },
    "WorkspaceIdGenerator": {
       "Name": "Full",
       "Value": 2,
       "Prefix": "org.su"
    },
    "ProvisioningType: 0
]

 

Workspaces

Main provisioning endpoint to create, update or remove workspaces on a given tenant.

Creating, updating or removing workspaces

Creating new workspace

POST /workspaces

 

Field Type Required Notes
WorkspaceId string Yes Site collection id that will be part of url.
Name string Yes Site collection name that will be part of title.
OrganizationUnitId guid Yes Id of the organization unit to which workspace belongs to.
WorkspaceTypeId guid Yes Id of workspace type. Note: Id must be in available workspace types list for given organization unit id.
Manager object Yes Manager of a workspace, provide email address of Azure AD.
Deputy object No Deputy of a workspace, provide email address of Azure AD.
Schema array No Must comply to schema of selected WorkspaceTypeId.
Team object No (Workspace)
Yes (Team)
Contains 'Added' and 'Removed' collections for updating members of a workspace team.
Description string No Site description of SharePoint or Teams Workspace.
ParentWorkspaceId string No Workspace ID of the parent Workspace.

'WorkspaceId' should be populated based on WorkspaceIdGenerator Type for a given 'OrganizationUnitId' and 'WorkspaceTypeId'.

  • None Generator Type: 'WorkspaceId' value should be populated and sent in the request body.

  • PrefixWithId Generator Type: 'WorkspaceId' value should be populated and sent starting with prefix for a given 'OrganizationUnitId' and 'WorkspaceTypeId'.

  • Full Generator Type: 'WorkspaceId' value is automatically generated and should not be sent in the request body.

  • PrefixWithName Generator Type: 'WorkspaceId' value is automatically generated containing prefix of a given 'OrganizationUnitId' and 'WorkspaceTypeId' and alpha numerics from Name. It should not be sent in the request body.

Based on selected 'WorkspaceTypeId' for a given 'OrganizationUnitId' and their ProvisioningType set in configuration, Teams Workspace will be created.

For Manager 'Email' field is required. Manager will be added to respective Managers and Members groups for a given workspace.

For Schema 'FieldName' and 'FieldValue' are required.

If the type of the workspace creation is a team, the Team field is required and needs to be populated with the Owners group and at least one valid owner.

For Team 'Added' is a collection that contains members to be added to specified groups. 'Group' and 'Members' fields are required in this collection.

For Team 'Removed' is a collection that contains members to be removed from specified groups. Currently not implemented on the workspace creation.

Group: Used for specifying group name to which members are added.

  • Allowed values for SharePoint Workspaces are: Managers, Members and Visitors. Members: List of accounts. Email or AD group name should be provided.

  • Allowed values for Teams Workspaces are: Owners and Members. Members: Should contain only accounts with valid email address and not AD groups.

  • Members defined as 'Added' for the Owners group will be automatically added to respective Owners and Members groups for a given workspace.

When creating Teams Workspaces if one account is specified more than once in Owners and/or Members groups only distinct members of these groups will be processed and added to specified groups.

Sample Request for creating new workspace:

POST api/tenantname/workspaces
Content-Type application/json
{
  "WorkspaceId": "pr.01",
  "Name": "Project01",
  "Description": "Project01 description"
  "OrganizationUnitId": "A787FB88-177F-4534-AC3A-A781AD9874D2",
  "WorkspaceTypeId": "6FF11D16-2F92-47EF-9EEA-06442125C38E",
  "ParentWorkspaceId": "parent-pr.01",
  "Manager": {
    "Name": "Marko",
    "Email": "marko@xyz.com"
  },
  "Deputy": {
    "Name": "Ana",
    "Email": "ana@xyz.com"
  },
  "Schema": [
    {
      "FieldName": "StartDate",
      "FieldType": "datetime",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "EndDate",
      "FieldType": "datetime",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "Customer",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "OrganizationalUnit",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "Description",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    }
  ],
  "Team": {
    "Added": [
      {
        "Group": "Owners",
        "Members": [
          "tom@xyz.com",
          "maria@xyz.com",
          "AD_XYZ"
        ]
      },
      {
        "Group": "Members",
        "Members": [
          "tom@xyz.com"
        ]
      }
    ]
  }
}
201 Created
Content-Type: application/json
{
  "WorkspaceId": "pr.01"
}

 

Updating workspace

Standard properties update
PUT workspaces/{workspaceId}

 

Field Type Required Notes
Name string Yes Site collection name.
LifeCycle int Yes One of: active(0), closed(1)
Manger object Yes Manager of a workspace, provide email address of Azure AD.
Deputy object Yes Deputy of a workspace, provide email address of Azure AD.
ParentWorkspaceId string No Workspace ID of the parent Workspace.

For Manager and Deputy 'Email' field is required.

New Manager will be added to respective Managers and Members groups for a given workspace. Old Manager will be only removed from Managers group for a given workspace.

Updating the name of the site collection will also update workspace group names and the name of the workspace notebook.

ParentWorkspaceId must be a valid Seamless Site. To remove the currently set parent workspace use an empty string "". The parent workspace will not be updated if the parameter is missing or null.


  

Sample Request for updating existing workspace:

PUT api/tenantname/workspaces/testWorkspace
Content-Type: application/json
{
  "Name": "Orange",
  "LifeCycle": 1,
  "ParentWorkspaceId": "Fruit",
  "Manager": {
    "Name": "Bob",
    "Email": "bob@xyz.com"
  },
  "Deputy": {
    "Name": "Anita",
    "Email": "anita@xyz.com"
  }
}
200 Ok
Content-Type: application/json
{
 "Name": "Orange",
 "LifeCycle": 1,
 "ParentWorkspaceId": "Fruit",
 "Manager": {
   "Name": "Bob",
   "Email": "bob@xyz.com"
 },
 "Deputy": {
   "Name": "Anita",
   "Email": "anita@xyz.com"
 }
}

 

Workspace team members update
PUT /workspaces/{workspaceId}/team

 

Endpoint is used for adding/removing members on existing workspace.

Field Type Notes
Added array Collection of members to be added to specified groups.
Removed array Collection of members to be removed from specified groups.

For Added/Removed collections 'Group' and 'Members' fields are required.

Group: Used for specifying group name to which members are added/removed. Must be the exact group name as returned by the get workspaces group endpoint.

Members: List of accounts (email or AD group name is allowed) to be added/removed to specified group.

Members defined as 'Added' for the Managers group will be automatically added to respective Managers and Members groups for a given workspace.


  

Sample Request for managing team of a workspace:

PUT api/tenantname/workspaces/testWorkspace/team
Content-Type: application/json
{
  "Added": [
    {
      "Group": "testWorkspace Managers",
      "Members": [
        "first@tenantname.onmicrosoft.com",
        "john@tenantname.onmicrosoft.com",
        "AD_Test"
      ]
    },
    {
      "Group": "testWorkspace Members",
      "Members": [
        "imp@tenantname.onmicrosoft.com"
      ]
    }
  ],
  "Removed": [
    {
      "Group": "testWorkspace People",
      "Members": [
        "imp@tenantname.onmicrosoft.com",
        "AD_Test"
      ]
    }
  ]
}
200 Ok
Content-Type: application/json
[
 {
   "Group": "testWorkspace Managers",
   "Members": [
     {
       "Account": "first@tenantname.onmicrosoft.com",
       "Status": 2
     },
     {
       "Account": "john@tenantname.onmicrosoft.com",
       "Status": 0
     },
     {
       "Account": "AD_Test",
       "Status": 0
     }
   ]
 },
 {
   "Group": "testWorkspace Members",
   "Members": [
     {
       "Account": "imp@tenantname.onmicrosoft.com",
       "Status": 1
     }
   ]
 },
 {
   "Group": "testWorkspace People",
   "Members": [
     {
       "Account": "imp@tenantname.onmicrosoft.com",
       "Status": 3
     },
     {
       "Account": "AD_Test",
       "Status": 3
     }
   ]
 }
]

Response contains necessary information about team members that are added/removed on/from specified groups on a given workspace. Status of each member after executing the team update can be: Added(0), Removed(1), Failed(2) or NotExistingGroup(3).

 

Workspace schema update
PUT workspaces/{workspaceId}/schema

 

Endpoint is used for updating schema properties of a given workspace. Field 'FieldValue' holds the value of the specified 'FieldName'. Schema 'FieldName's must be matched with all 'FieldName's defined in the workspace type.

Field Type Notes
FieldName string The name of a field that needs to be populated.
FieldValue string Value to be set on a given field.

Sample Request for updating existing workspace schema definition:

PUT api/tenantname/workspaces/testWorkspace/schema
Content-Type: application/json
[
  {
    "FieldName": "StartDate",
    "FieldValue": null
  },
  {
    "FieldName": "EndDate",
    "FieldValue": null
  },
  {
    "FieldName": "Customer",
    "FieldValue": "Migros"
  },
  {
    "FieldName": "Description",
    "FieldValue": "Store chain"
  }
]
200 Ok
Content-Type: application/json
{
   "WorkspaceId": "testWorkspace",
   "Url": "https://askmwewhy.sharepoint.com/sites/pr.01",
   "Schema": "[{\"FieldName\":\"StartDate\",\"FieldType\":\"datetime\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null},
   {\"FieldName\":\"EndDate\",\"FieldType\":\"datetime\",\"FieldValue\":null,\"IsRequired\":false,\"ValidValues\":null},
   {\"FieldName\":\"Customer\",\"FieldType\":\"string\",\"FieldValue\":\"Migros\",\"IsRequired\":false,\"ValidValues\":null},
   {\"FieldName\":\"Description\",\"FieldType\":\"string\",\"FieldValue\":\"Store chain\",\"IsRequired\":false,\"ValidValues\":null}]"
}

 

Workspace type update
PUT workspaces/{workspaceId}/workspaceType

 

Endpoint is used for updating workspace type of a given workspace. The workspace type update also updates list of provisioned tools for a given workspace.

Field Type Notes
Id guid Id of a workspace type.

New workspace type should be available for current Organization Unit of a given workspace.

New workspace type should have matching Schema as current workspace type of a given workspace.

New workspace type should have WorkspaceIdPrefix for which current WorkspaceId of a given workspace starts, for Semi and Full WorkspaceIdGeneratorType.

Sample Request for updating existing workspace type:

PUT api/tenantname/workspaces/testWorkspace/workspaceType
Content-Type: application/json
{
   "Id": "24760C3C-0E37-457B-B51B-8D1B235382F1"
}
200 Ok
Content-Type: application/json
{
   "WorkspaceId": "testWorkspace",
   "Url": "https://askmwewhy.sharepoint.com/sites/pr.01",
   "UnitTypeId": "3",
   "Cards": [
     {
       "Title": "Tasks",
       "ListName": "Tasks",
       "IsRestricted": false
     }
   ]
}

 

Get existing workspace

GET /workspaces/{workspaceId}

Endpoint is used for getting information about a given workspace. It can be used to check workspace stage(status), life cycle, etc.

Field Type Notes
Id int Unique workspace id.
Stage int One of: forprovisioning(0), provisioning(1), ready(2), failed(3), partiallyready(4)
WorkspaceId string Workspace id which is part of a url.
Name string Title of a workspace.
UnitTypeId int Id to determine to which organization unit and workspace type workspace belongs to.
Url string Url to the site collection on sharepoint tenant.
Shared boolean Sharing of a workspace.
ParentWorkspaceId string Workspace ID of the parent Workspace. null if there is none.
LifeCycle int One of: active(0), closed(1)
TeamsUrl string Url to the Microsoft Teams Room when workspace is type of Teams. null for SharePoint workspaces.
Created datetime Creation date of a workspace.
Modified datetime Last modification date of a workspace.
Creator object Creator of a workspace.
Modifier object Last modifier of a workspace.
Manger object Manager of a workspace.
Deputy object Deputy of a workspace.
Cards array List of provisioned tools of a workspace.
Schema array Schema of a workspace.


Sample Request for getting existing workspace:

GET api/tenantname/workspaces/example
200 OK
Content-Type: application/json
{
  "Id": 69,
  "Stage": 2,
  "WorkspaceId": "example",
  "Name": "Project01",
  "UnitTypeId": 2,
  "Url": "https://tenantname.sharepoint.com/sites/example",
  "Shared": false,
  "ParentWorkspaceId": "Customer-1",
  "LifeCycle": 0,
  "Created": "2019-03-29T12:05:49Z",
  "Modified": "2019-03-29T12:05:49Z",
  "TeamsUrl": "https://teams.microsoft.com/l/team/19%3rt836f5054ahh4v48861156239ebyfe81%40thread.skype/conversations?groupId=9e6c7c6b-53e5-4fbb-859e-845b10410cff&tenantId=e47fcd9f-ec5b-4d3e-af41-9a4953b5b166",
  "Creator": {
    "Name": "Seamless Admin",
    "Email": "seamless@tenantname.onmicrosoft.com"
  },
  "Modifier": {
    "Name": "Seamless Admin",
    "Email": "seamless@tenantname.onmicrosoft.com"
  },
  "Manager": {
    "Email": "seamless@tenantname.onmicrosoft.com",
    "Name": "Seamless Admin"
  },
  "Deputy": {
    "Name": "Seamless Admin",
    "Email": "seamless@tenantname.onmicrosoft.com"
  },
  "Cards": [
    {
      "Title": "Documents",
      "ListName": "Documents",
      "IsRestricted": false
    },
    {
      "Title": "Tasks",
      "ListName": "Tasks",
      "IsRestricted": false
    },
    {
      "Title": "Work Breakdown Structure",
      "ListName": "WorkBreakdownStructure",
      "IsRestricted": false
    }
  ],
  "Schema": [
    {
      "FieldName": "StartDate",
      "FieldType": "datetime",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "EndDate",
      "FieldType": "datetime",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "Customer",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "OrganizationalUnit",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    },
    {
      "FieldName": "Description",
      "FieldType": "string",
      "FieldValue": null,
      "IsRequired": false,
      "ValidValues": null
    }
  ]
}

 

Get status of a workspace

GET /workspaces/{workspaceId}/status

Endpoint is used for getting current status for a given workspace. Workspace can have following status codes: ForProvisioning(0), Provisioning(1), Ready(2), Failed(3), Updating(4), ForDeletion(5)

Sample Request for getting status of a existing workspace:

GET api/tenantname/workspaces/testWorkspace/status
200 OK
Content-Type: application/json
{
"Name": "Ready",
"Value": 2
}

 

Get workspace groups

GET /workspaces/{workspaceId}/groups

Endpoint is used for getting site groups for a given workspace.

Sample Request for getting site groups for a given workspace:

GET api/tenantname/workspaces/testWorkspace/groups
200 OK
Content-Type: application/json
"Groups": [
   "testWorkspace Managers",
   "testWorkspace Members",
   "testWorkspace Owners",
   "testWorkspace Visitors"
]

 

Get workspace team

GET /workspaces/{workspaceId}/team

Endpoint is used for getting workspace team members.

Sample Request for getting team members for a given workspace:

GET api/tenantname/workspaces/testWorkspace/team
200 OK
Content-Type: application/json
[
 {
   "Group": "Excel Services Viewers",
   "Members": []
 },
 {
   "Group": "testWorkspace Managers",
   "Members": [
     "first@tenantname.onmicrosoft.com",
     "john@tenantname.onmicrosoft.com",
     "AD_Test"
   ]
 },
 {
   "Group": "testWorkspace Members",
   "Members": [
     "imp@tenantname.onmicrosoft.com"
   ]
 },
 {
   "Group": "testWorkspace Owners",
   "Members": [
     "System Account"
   ]
 },
 {
   "Group": "testWorkspace Visitors",
   "Members": [
     "michael@tenantname.onmicrosoft.com",
     "lucas@tenantname.onmicrosoft.com",
     "AD_Visitors_Test"
   ]
 }
]

 

© 2021 AskMeWhy AG
Prev {[{nav.prev.title}]}
Next {[{nav.next.title}]}
AskMeWhy AG

Seamless is a brand and/or register trademark of AskMeWhy AG in Switzerland and/or other country.

Other names and/or images of companies, products or services can be brands or registered trademarks of the acknowledged owner.

© AskMeWhy AG 2019