Repository: ctreminiom/go-atlassian
Pull request #204 (2023-05-28 06:39:32)

:building_construction: Created the Jira Assets module
1. Created the service interfaces for the Assets icons,AQL, and object's.


Patch:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index f2c44d4..95fa7e3 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -39,7 +39,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
         languages: ${{ matrix.language }}
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
     # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
     # If this step fails, then you should remove it and run the build manually (see below)
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
 
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
@@ -64,4 +64,4 @@ jobs:
     #   make release
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      uses: github/codeql-action/analyze@v2
diff --git a/assets/api_client_impl.go b/assets/api_client_impl.go
new file mode 100644
index 0000000..b9bd7f9
--- /dev/null
+++ b/assets/api_client_impl.go
@@ -0,0 +1,161 @@
+package assets
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"github.com/ctreminiom/go-atlassian/assets/internal"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service/common"
+	"io"
+	"net/http"
+	"net/url"
+)
+
+const DefaultAssetsSite = "https://api.atlassian.com/"
+
+func New(httpClient common.HttpClient, site string) (*Client, error) {
+
+	if httpClient == nil {
+		httpClient = http.DefaultClient
+	}
+
+	if site == "" {
+		site = DefaultAssetsSite
+	}
+
+	u, err := url.Parse(site)
+	if err != nil {
+		return nil, err
+	}
+
+	client := &Client{
+		HTTP: httpClient,
+		Site: u,
+	}
+
+	client.Auth = internal.NewAuthenticationService(client)
+
+	// Assets services
+	client.AQL = internal.NewAQLService(client)
+	client.Icon = internal.NewIconService(client)
+	client.Object = internal.NewObjectService(client)
+	client.ObjectSchema = internal.NewObjectSchemaService(client)
+	client.ObjectType = internal.NewObjectTypeService(client)
+	client.ObjectTypeAttribute = internal.NewObjectTypeAttributeService(client)
+
+	return client, nil
+}
+
+type Client struct {
+	HTTP                common.HttpClient
+	Site                *url.URL
+	Auth                common.Authentication
+	AQL                 *internal.AQLService
+	Icon                *internal.IconService
+	Object              *internal.ObjectService
+	ObjectSchema        *internal.ObjectSchemaService
+	ObjectType          *internal.ObjectTypeService
+	ObjectTypeAttribute *internal.ObjectTypeAttributeService
+}
+
+func (c *Client) NewRequest(ctx context.Context, method, urlStr, type_ string, body interface{}) (*http.Request, error) {
+
+	rel, err := url.Parse(urlStr)
+	if err != nil {
+		return nil, err
+	}
+
+	u := c.Site.ResolveReference(rel)
+
+	buf := new(bytes.Buffer)
+	if body != nil {
+		if err = json.NewEncoder(buf).Encode(body); err != nil {
+			return nil, err
+		}
+	}
+
+	req, err := http.NewRequestWithContext(ctx, method, u.String(), buf)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Accept", "application/json")
+
+	if body != nil && type_ == "" {
+		req.Header.Set("Content-Type", "application/json")
+	}
+
+	if body != nil && type_ != "" {
+		req.Header.Set("Content-Type", type_)
+	}
+
+	if c.Auth.HasBasicAuth() {
+		req.SetBasicAuth(c.Auth.GetBasicAuth())
+	}
+
+	if c.Auth.HasUserAgent() {
+		req.Header.Set("User-Agent", c.Auth.GetUserAgent())
+	}
+
+	return req, nil
+}
+
+func (c *Client) Call(request *http.Request, structure interface{}) (*model.ResponseScheme, error) {
+
+	response, err := c.HTTP.Do(request)
+	if err != nil {
+		return nil, err
+	}
+
+	return c.processResponse(response, structure)
+}
+
+func (c *Client) processResponse(response *http.Response, structure interface{}) (*model.ResponseScheme, error) {
+
+	defer response.Body.Close()
+
+	res := &model.ResponseScheme{
+		Response: response,
+		Code:     response.StatusCode,
+		Endpoint: response.Request.URL.String(),
+		Method:   response.Request.Method,
+	}
+
+	responseAsBytes, err := io.ReadAll(response.Body)
+	if err != nil {
+		return res, err
+	}
+
+	res.Bytes.Write(responseAsBytes)
+
+	wasSuccess := response.StatusCode >= 200 && response.StatusCode < 300
+
+	if !wasSuccess {
+
+		switch response.StatusCode {
+
+		case http.StatusNotFound:
+			return res, model.ErrNotFound
+
+		case http.StatusUnauthorized:
+			return res, model.ErrUnauthorized
+
+		case http.StatusInternalServerError:
+			return res, model.ErrInternalError
+
+		case http.StatusBadRequest:
+			return res, model.ErrBadRequestError
+
+		default:
+			return res, model.ErrInvalidStatusCodeError
+		}
+	}
+
+	if structure != nil {
+		if err = json.Unmarshal(responseAsBytes, &structure); err != nil {
+			return res, err
+		}
+	}
+
+	return res, nil
+}
diff --git a/assets/internal/aql_impl.go b/assets/internal/aql_impl.go
new file mode 100644
index 0000000..1f93c12
--- /dev/null
+++ b/assets/internal/aql_impl.go
@@ -0,0 +1,78 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+func NewAQLService(client service.Connector) *AQLService {
+
+	return &AQLService{
+		internalClient: &internalAQLImpl{c: client},
+	}
+}
+
+type AQLService struct {
+	internalClient assets.AQLAssetConnector
+}
+
+// Filter search objects based on Assets Query Language (AQL)
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/aql/objects
+//
+// Deprecated. Please use Object.Filter() instead.
+//
+// https://docs.go-atlassian.io/jira-assets/aql#filter-objects
+func (a *AQLService) Filter(ctx context.Context, workspaceID string, parameters *model.AQLSearchParamsScheme) (*model.ObjectListScheme, *model.ResponseScheme, error) {
+	return a.internalClient.Filter(ctx, workspaceID, parameters)
+}
+
+type internalAQLImpl struct {
+	c service.Connector
+}
+
+func (i *internalAQLImpl) Filter(ctx context.Context, workspaceID string, parameters *model.AQLSearchParamsScheme) (*model.ObjectListScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("jsm/assets/workspace/%v/v1/aql/objects", workspaceID))
+
+	if parameters != nil {
+
+		query := url.Values{}
+		query.Add("qlQuery", parameters.Query)
+		query.Add("page", strconv.Itoa(parameters.Page))
+		query.Add("resultPerPage", strconv.Itoa(parameters.ResultPerPage))
+		query.Add("includeAttributes", fmt.Sprintf("%v", parameters.IncludeAttributes))
+		query.Add("includeAttributesDeep", fmt.Sprintf("%v", parameters.IncludeAttributesDeep))
+		query.Add("includeTypeAttributes", fmt.Sprintf("%v", parameters.IncludeTypeAttributes))
+		query.Add("includeExtendedInfo", fmt.Sprintf("%v", parameters.IncludeExtendedInfo))
+
+		if query.Encode() != "" {
+			endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+		}
+	}
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	object := new(model.ObjectListScheme)
+	res, err := i.c.Call(req, object)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return object, res, nil
+}
diff --git a/assets/internal/authentication_impl.go b/assets/internal/authentication_impl.go
new file mode 100644
index 0000000..2bbe9ab
--- /dev/null
+++ b/assets/internal/authentication_impl.go
@@ -0,0 +1,61 @@
+package internal
+
+import (
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/common"
+)
+
+func NewAuthenticationService(client service.Connector) common.Authentication {
+	return &AuthenticationService{c: client}
+}
+
+type AuthenticationService struct {
+	c service.Connector
+
+	basicAuthProvided bool
+	mail, token       string
+
+	userAgentProvided bool
+	agent             string
+}
+
+func (a *AuthenticationService) SetBearerToken(token string) {
+	a.token = token
+}
+
+func (a *AuthenticationService) GetBearerToken() string {
+	return a.token
+}
+func (a *AuthenticationService) SetExperimentalFlag() {}
+
+func (a *AuthenticationService) HasSetExperimentalFlag() bool {
+	return false
+}
+
+func (a *AuthenticationService) SetBasicAuth(mail, token string) {
+	a.mail = mail
+	a.token = token
+
+	a.basicAuthProvided = true
+}
+
+func (a *AuthenticationService) GetBasicAuth() (string, string) {
+	return a.mail, a.token
+}
+
+func (a *AuthenticationService) HasBasicAuth() bool {
+	return a.basicAuthProvided
+}
+
+func (a *AuthenticationService) SetUserAgent(agent string) {
+	a.agent = agent
+	a.userAgentProvided = true
+}
+
+func (a *AuthenticationService) GetUserAgent() string {
+	return a.agent
+}
+
+func (a *AuthenticationService) HasUserAgent() bool {
+	return a.userAgentProvided
+}
diff --git a/assets/internal/icon_impl.go b/assets/internal/icon_impl.go
new file mode 100644
index 0000000..b97eb70
--- /dev/null
+++ b/assets/internal/icon_impl.go
@@ -0,0 +1,91 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+)
+
+func NewIconService(client service.Connector) *IconService {
+
+	return &IconService{
+		internalClient: &internalIconImpl{c: client},
+	}
+}
+
+type IconService struct {
+	internalClient assets.IconConnector
+}
+
+// Get loads a single asset icon by id.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/icon/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/icons#get-icon
+func (i *IconService) Get(ctx context.Context, workspaceID, iconID string) (*model.IconScheme, *model.ResponseScheme, error) {
+	return i.internalClient.Get(ctx, workspaceID, iconID)
+}
+
+// Global returns all global icons i.e. icons not associated with a particular object schema.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/icon/global
+//
+// https://docs.go-atlassian.io/jira-assets/icons#get-global-icons
+func (i *IconService) Global(ctx context.Context, workspaceID string) ([]*model.IconScheme, *model.ResponseScheme, error) {
+	return i.internalClient.Global(ctx, workspaceID)
+}
+
+type internalIconImpl struct {
+	c service.Connector
+}
+
+func (i *internalIconImpl) Get(ctx context.Context, workspaceID, iconID string) (*model.IconScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if iconID == "" {
+		return nil, nil, model.ErrNoIconIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/icon/%v", workspaceID, iconID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	icon := new(model.IconScheme)
+	res, err := i.c.Call(req, icon)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return icon, res, nil
+}
+
+func (i *internalIconImpl) Global(ctx context.Context, workspaceID string) ([]*model.IconScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/icon/global", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var icons []*model.IconScheme
+	res, err := i.c.Call(req, &icons)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return icons, res, nil
+}
diff --git a/assets/internal/object_impl.go b/assets/internal/object_impl.go
new file mode 100644
index 0000000..fa5494f
--- /dev/null
+++ b/assets/internal/object_impl.go
@@ -0,0 +1,384 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+func NewObjectService(client service.Connector) *ObjectService {
+
+	return &ObjectService{
+		internalClient: &internalObjectImpl{c: client},
+	}
+}
+
+type ObjectService struct {
+	internalClient assets.ObjectConnector
+}
+
+// Get loads one object.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object#get-object-by-id
+func (o *ObjectService) Get(ctx context.Context, workspaceID, objectID string) (*model.ObjectScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Get(ctx, workspaceID, objectID)
+}
+
+// Update updates an existing object in Assets.
+//
+// PUT /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object#update-object-by-id
+func (o *ObjectService) Update(ctx context.Context, workspaceID, objectID string, payload *model.ObjectPayloadScheme) (*model.ObjectScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Update(ctx, workspaceID, objectID, payload)
+}
+
+// Delete deletes the referenced object
+//
+// DELETE /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object#delete-object-by-id
+func (o *ObjectService) Delete(ctx context.Context, workspaceID, objectID string) (*model.ResponseScheme, error) {
+	return o.internalClient.Delete(ctx, workspaceID, objectID)
+}
+
+// Attributes list all attributes for the given object.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/attributes
+//
+// https://docs.go-atlassian.io/jira-assets/object#get-object-attributes
+func (o *ObjectService) Attributes(ctx context.Context, workspaceID, objectID string) ([]*model.ObjectAttributeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Attributes(ctx, workspaceID, objectID)
+}
+
+// History retrieves the history entries for this object.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/history
+//
+// https://docs.go-atlassian.io/jira-assets/object#get-object-changelogs
+func (o *ObjectService) History(ctx context.Context, workspaceID, objectID string, ascOrder bool) ([]*model.ObjectHistoryScheme, *model.ResponseScheme, error) {
+	return o.internalClient.History(ctx, workspaceID, objectID, ascOrder)
+}
+
+// References finds all references for an object.
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/referenceinfo
+//
+// https://docs.go-atlassian.io/jira-assets/object#get-object-references
+func (o *ObjectService) References(ctx context.Context, workspaceID, objectID string) ([]*model.ObjectReferenceTypeInfoScheme, *model.ResponseScheme, error) {
+	return o.internalClient.References(ctx, workspaceID, objectID)
+}
+
+// Create creates a new object in Assets.
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/object/create
+//
+// https://docs.go-atlassian.io/jira-assets/object#create-object
+func (o *ObjectService) Create(ctx context.Context, workspaceID string, payload *model.ObjectPayloadScheme) (*model.ObjectScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Create(ctx, workspaceID, payload)
+}
+
+// Relation returns the relation between Jira issues and Assets objects
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objectconnectedtickets/{objectId}/tickets
+//
+// https://docs.go-atlassian.io/jira-assets/object#get-object-tickets
+func (o *ObjectService) Relation(ctx context.Context, workspaceID, objectID string) (*model.TicketPageScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Relation(ctx, workspaceID, objectID)
+}
+
+// Filter fetch Objects by AQL.
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/object/aql
+//
+// https://docs.go-atlassian.io/jira-assets/object#filter-objects
+func (o *ObjectService) Filter(ctx context.Context, workspaceID, aql string, attributes bool, startAt, maxResults int) (*model.ObjectListResultScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Filter(ctx, workspaceID, aql, attributes, startAt, maxResults)
+}
+
+// Search retrieve a list of objects based on an AQL.
+//
+// Note that the preferred endpoint is /aql
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/object/navlist/aql
+//
+// https://docs.go-atlassian.io/jira-assets/object#search-objects
+func (o *ObjectService) Search(ctx context.Context, workspaceID string, payload *model.ObjectSearchParamsScheme) (*model.ObjectListScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Search(ctx, workspaceID, payload)
+}
+
+type internalObjectImpl struct {
+	c service.Connector
+}
+
+func (i *internalObjectImpl) Search(ctx context.Context, workspaceID string, payload *model.ObjectSearchParamsScheme) (*model.ObjectListScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/navlist/aql", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	object := new(model.ObjectListScheme)
+	res, err := i.c.Call(req, object)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return object, res, nil
+
+}
+
+func (i *internalObjectImpl) Filter(ctx context.Context, workspaceID, aql string, attributes bool, startAt, maxResults int) (*model.ObjectListResultScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if aql == "" {
+		return nil, nil, model.ErrNoAqlQueryError
+	}
+
+	params := url.Values{}
+	params.Add("startAt", strconv.Itoa(startAt))
+	params.Add("maxResults", strconv.Itoa(maxResults))
+
+	if !attributes {
+		params.Add("includeAttributes", "false")
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/aql?%v", workspaceID, params.Encode())
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", map[string]interface{}{"qlQuery": aql})
+	if err != nil {
+		return nil, nil, err
+	}
+
+	list := new(model.ObjectListResultScheme)
+	res, err := i.c.Call(req, list)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return list, res, nil
+}
+
+func (i *internalObjectImpl) Get(ctx context.Context, workspaceID, objectID string) (*model.ObjectScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	object := new(model.ObjectScheme)
+	res, err := i.c.Call(req, object)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return object, res, nil
+}
+
+func (i *internalObjectImpl) Update(ctx context.Context, workspaceID, objectID string, payload *model.ObjectPayloadScheme) (*model.ObjectScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	object := new(model.ObjectScheme)
+	res, err := i.c.Call(req, object)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return object, res, nil
+}
+
+func (i *internalObjectImpl) Delete(ctx context.Context, workspaceID, objectID string) (*model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return i.c.Call(req, nil)
+}
+
+func (i *internalObjectImpl) Attributes(ctx context.Context, workspaceID, objectID string) ([]*model.ObjectAttributeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v/attributes", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var attributes []*model.ObjectAttributeScheme
+	res, err := i.c.Call(req, &attributes)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return attributes, res, nil
+}
+
+func (i *internalObjectImpl) History(ctx context.Context, workspaceID, objectID string, ascOrder bool) ([]*model.ObjectHistoryScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v/history", workspaceID, objectID))
+
+	if ascOrder {
+
+		query := url.Values{}
+		query.Add("asc", "true")
+
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var history []*model.ObjectHistoryScheme
+	res, err := i.c.Call(req, &history)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return history, res, nil
+}
+
+func (i *internalObjectImpl) References(ctx context.Context, workspaceID, objectID string) ([]*model.ObjectReferenceTypeInfoScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/%v/referenceinfo", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var references []*model.ObjectReferenceTypeInfoScheme
+	res, err := i.c.Call(req, &references)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return references, res, nil
+}
+
+func (i *internalObjectImpl) Create(ctx context.Context, workspaceID string, payload *model.ObjectPayloadScheme) (*model.ObjectScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/object/create", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	object := new(model.ObjectScheme)
+	res, err := i.c.Call(req, object)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return object, res, nil
+}
+
+func (i *internalObjectImpl) Relation(ctx context.Context, workspaceID, objectID string) (*model.TicketPageScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectID == "" {
+		return nil, nil, model.ErrNoObjectIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectconnectedtickets/%v/tickets", workspaceID, objectID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	page := new(model.TicketPageScheme)
+	res, err := i.c.Call(req, page)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return page, res, nil
+}
diff --git a/assets/internal/object_schema_impl.go b/assets/internal/object_schema_impl.go
new file mode 100644
index 0000000..db3c4f3
--- /dev/null
+++ b/assets/internal/object_schema_impl.go
@@ -0,0 +1,297 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+func NewObjectSchemaService(client service.Connector) *ObjectSchemaService {
+
+	return &ObjectSchemaService{
+		internalClient: &internalObjectSchemaImpl{c: client},
+	}
+}
+
+type ObjectSchemaService struct {
+	internalClient assets.ObjectSchemaConnector
+}
+
+// List returns all the object schemas available on Assets
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/list
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-list
+func (o *ObjectSchemaService) List(ctx context.Context, workspaceID string) (*model.ObjectSchemaPageScheme, *model.ResponseScheme, error) {
+	return o.internalClient.List(ctx, workspaceID)
+}
+
+// Create creates a new object schema
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/objectschema/create
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#create-object-schema
+func (o *ObjectSchemaService) Create(ctx context.Context, workspaceID string, payload *model.ObjectSchemaPayloadScheme) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Create(ctx, workspaceID, payload)
+}
+
+// Get returns an object schema by ID
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema
+func (o *ObjectSchemaService) Get(ctx context.Context, workspaceID, objectSchemaID string) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Get(ctx, workspaceID, objectSchemaID)
+}
+
+// Update updates an object schema
+//
+// PUT /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#update-object-schema
+func (o *ObjectSchemaService) Update(ctx context.Context, workspaceID, objectSchemaID string, payload *model.ObjectSchemaPayloadScheme) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Update(ctx, workspaceID, objectSchemaID, payload)
+}
+
+// Delete deletes a schema
+//
+// DELETE /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#delete-object-schema
+func (o *ObjectSchemaService) Delete(ctx context.Context, workspaceID, objectSchemaID string) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Delete(ctx, workspaceID, objectSchemaID)
+}
+
+// Attributes finds all object type attributes for this object schema
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}/attributes
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-attributes
+func (o *ObjectSchemaService) Attributes(ctx context.Context, workspaceID, objectSchemaID string, options *model.ObjectSchemaAttributesParamsScheme) ([]*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Attributes(ctx, workspaceID, objectSchemaID, options)
+}
+
+// ObjectTypes returns all object types for this object schema
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}/objecttypes
+//
+// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-types
+func (o *ObjectSchemaService) ObjectTypes(ctx context.Context, workspaceID, objectSchemaID string, excludeAbstract bool) ([]*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.ObjectTypes(ctx, workspaceID, objectSchemaID, excludeAbstract)
+}
+
+type internalObjectSchemaImpl struct {
+	c service.Connector
+}
+
+func (i *internalObjectSchemaImpl) List(ctx context.Context, workspaceID string) (*model.ObjectSchemaPageScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/list", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	page := new(model.ObjectSchemaPageScheme)
+	res, err := i.c.Call(req, page)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return page, res, nil
+}
+
+func (i *internalObjectSchemaImpl) Create(ctx context.Context, workspaceID string, payload *model.ObjectSchemaPayloadScheme) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/create", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	schema := new(model.ObjectSchemaScheme)
+	res, err := i.c.Call(req, schema)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return schema, res, nil
+}
+
+func (i *internalObjectSchemaImpl) Get(ctx context.Context, workspaceID, objectSchemaID string) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectSchemaID == "" {
+		return nil, nil, model.ErrNoObjectSchemaIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/%v", workspaceID, objectSchemaID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	schema := new(model.ObjectSchemaScheme)
+	res, err := i.c.Call(req, schema)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return schema, res, nil
+}
+
+func (i *internalObjectSchemaImpl) Update(ctx context.Context, workspaceID, objectSchemaID string, payload *model.ObjectSchemaPayloadScheme) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectSchemaID == "" {
+		return nil, nil, model.ErrNoObjectSchemaIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/%v", workspaceID, objectSchemaID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	schema := new(model.ObjectSchemaScheme)
+	res, err := i.c.Call(req, schema)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return schema, res, nil
+}
+
+func (i *internalObjectSchemaImpl) Delete(ctx context.Context, workspaceID, objectSchemaID string) (*model.ObjectSchemaScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectSchemaID == "" {
+		return nil, nil, model.ErrNoObjectSchemaIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/%v", workspaceID, objectSchemaID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	schema := new(model.ObjectSchemaScheme)
+	res, err := i.c.Call(req, schema)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return schema, res, nil
+}
+
+func (i *internalObjectSchemaImpl) Attributes(ctx context.Context, workspaceID, objectSchemaID string, options *model.ObjectSchemaAttributesParamsScheme) ([]*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectSchemaID == "" {
+		return nil, nil, model.ErrNoObjectSchemaIDError
+	}
+
+	query := url.Values{}
+	if options != nil {
+
+		if options.OnlyValueEditable {
+			query.Add("onlyValueEditable", "true")
+		}
+
+		if options.OnlyValueEditable {
+			query.Add("onlyValueEditable", "true")
+		}
+
+		if options.Extended {
+			query.Add("extended", "true")
+		}
+
+		if options.Query != "" {
+			query.Add("query", options.Query)
+		}
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/%v/attributes", workspaceID, objectSchemaID))
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var attributes []*model.ObjectTypeAttributeScheme
+	res, err := i.c.Call(req, &attributes)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return attributes, res, nil
+}
+
+func (i *internalObjectSchemaImpl) ObjectTypes(ctx context.Context, workspaceID, objectSchemaID string, excludeAbstract bool) ([]*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectSchemaID == "" {
+		return nil, nil, model.ErrNoObjectSchemaIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("jsm/assets/workspace/%v/v1/objectschema/%v/objecttypes", workspaceID, objectSchemaID))
+
+	if excludeAbstract {
+		query := url.Values{}
+		query.Add("excludeAbstract", "true")
+
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var objectTypes []*model.ObjectTypeScheme
+	res, err := i.c.Call(req, &objectTypes)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectTypes, res, nil
+}
diff --git a/assets/internal/object_type_attribute_impl.go b/assets/internal/object_type_attribute_impl.go
new file mode 100644
index 0000000..5d1464b
--- /dev/null
+++ b/assets/internal/object_type_attribute_impl.go
@@ -0,0 +1,128 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+)
+
+func NewObjectTypeAttributeService(client service.Connector) *ObjectTypeAttributeService {
+
+	return &ObjectTypeAttributeService{
+		internalClient: &internalObjectTypeAttributeImpl{c: client},
+	}
+}
+
+type ObjectTypeAttributeService struct {
+	internalClient assets.ObjectTypeAttributeConnector
+}
+
+// Create creates a new attribute on the given object type
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{objectTypeId}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type/attribute#create-object-type-attribute
+func (o *ObjectTypeAttributeService) Create(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypeAttributeScheme) (*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Create(ctx, workspaceID, objectTypeID, payload)
+}
+
+// Update updates an existing object type attribute
+//
+// PUT /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{objectTypeId}/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type/attribute#update-object-type-attribute
+func (o *ObjectTypeAttributeService) Update(ctx context.Context, workspaceID, objectTypeID, attributeID string, payload *model.ObjectTypeAttributeScheme) (*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Update(ctx, workspaceID, objectTypeID, attributeID, payload)
+}
+
+// Delete deletes an existing object type attribute
+//
+// DELETE /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type/attribute#delete-object-type-attribute
+func (o *ObjectTypeAttributeService) Delete(ctx context.Context, workspaceID, attributeID string) (*model.ResponseScheme, error) {
+	return o.internalClient.Delete(ctx, workspaceID, attributeID)
+}
+
+type internalObjectTypeAttributeImpl struct {
+	c service.Connector
+}
+
+func (i *internalObjectTypeAttributeImpl) Create(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypeAttributeScheme) (*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttypeattribute/%v", workspaceID, objectTypeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	attribute := new(model.ObjectTypeAttributeScheme)
+	res, err := i.c.Call(req, attribute)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return attribute, res, nil
+}
+
+func (i *internalObjectTypeAttributeImpl) Update(ctx context.Context, workspaceID, objectTypeID, attributeID string, payload *model.ObjectTypeAttributeScheme) (*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	if attributeID == "" {
+		return nil, nil, model.ErrNoObjectTypeAttributeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttypeattribute/%v/%v", workspaceID, objectTypeID, attributeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	attribute := new(model.ObjectTypeAttributeScheme)
+	res, err := i.c.Call(req, attribute)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return attribute, res, nil
+}
+
+func (i *internalObjectTypeAttributeImpl) Delete(ctx context.Context, workspaceID, attributeID string) (*model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, model.ErrNoWorkspaceIDError
+	}
+
+	if attributeID == "" {
+		return nil, model.ErrNoObjectTypeAttributeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttypeattribute/%v", workspaceID, attributeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return i.c.Call(req, nil)
+}
diff --git a/assets/internal/object_type_impl.go b/assets/internal/object_type_impl.go
new file mode 100644
index 0000000..53319d5
--- /dev/null
+++ b/assets/internal/object_type_impl.go
@@ -0,0 +1,270 @@
+package internal
+
+import (
+	"context"
+	"fmt"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/assets"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+func NewObjectTypeService(client service.Connector) *ObjectTypeService {
+
+	return &ObjectTypeService{
+		internalClient: &internalObjectTypeImpl{c: client},
+	}
+}
+
+type ObjectTypeService struct {
+	internalClient assets.ObjectTypeConnector
+}
+
+// Get finds an object type by id
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#get-object-type
+func (o *ObjectTypeService) Get(ctx context.Context, workspaceID, objectTypeID string) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Get(ctx, workspaceID, objectTypeID)
+}
+
+// Update updates an existing object type
+//
+// PUT /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#update-object-type
+func (o *ObjectTypeService) Update(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypePayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Update(ctx, workspaceID, objectTypeID, payload)
+}
+
+// Create creates a new object type
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/objecttype/create
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#create-object-type
+func (o *ObjectTypeService) Create(ctx context.Context, workspaceID string, payload *model.ObjectTypePayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Create(ctx, workspaceID, payload)
+}
+
+// Delete deletes an object type
+//
+// DELETE /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#delete-object-type
+func (o *ObjectTypeService) Delete(ctx context.Context, workspaceID, objectTypeID string) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Delete(ctx, workspaceID, objectTypeID)
+}
+
+// Attributes finds all attributes for this object type
+//
+// GET /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}/attributes
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#get-object-type-attributes
+func (o *ObjectTypeService) Attributes(ctx context.Context, workspaceID, objectTypeID string, options *model.ObjectTypeAttributesParamsScheme) ([]*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Attributes(ctx, workspaceID, objectTypeID, options)
+}
+
+// Position changes the position of this object type
+//
+// POST /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}/position
+//
+// https://docs.go-atlassian.io/jira-assets/object/type#update-object-type-position
+func (o *ObjectTypeService) Position(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypePositionPayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+	return o.internalClient.Position(ctx, workspaceID, objectTypeID, payload)
+}
+
+type internalObjectTypeImpl struct {
+	c service.Connector
+}
+
+func (i *internalObjectTypeImpl) Get(ctx context.Context, workspaceID, objectTypeID string) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/%v", workspaceID, objectTypeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	objectType := new(model.ObjectTypeScheme)
+	res, err := i.c.Call(req, objectType)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectType, res, nil
+}
+
+func (i *internalObjectTypeImpl) Update(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypePayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/%v", workspaceID, objectTypeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	objectType := new(model.ObjectTypeScheme)
+	res, err := i.c.Call(req, objectType)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectType, res, nil
+}
+
+func (i *internalObjectTypeImpl) Create(ctx context.Context, workspaceID string, payload *model.ObjectTypePayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/create", workspaceID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	objectType := new(model.ObjectTypeScheme)
+	res, err := i.c.Call(req, objectType)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectType, res, nil
+}
+
+func (i *internalObjectTypeImpl) Delete(ctx context.Context, workspaceID, objectTypeID string) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/%v", workspaceID, objectTypeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	objectType := new(model.ObjectTypeScheme)
+	res, err := i.c.Call(req, objectType)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectType, res, nil
+}
+
+func (i *internalObjectTypeImpl) Attributes(ctx context.Context, workspaceID, objectTypeID string, options *model.ObjectTypeAttributesParamsScheme) ([]*model.ObjectTypeAttributeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/%v/attributes", workspaceID, objectTypeID))
+
+	query := url.Values{}
+	if options != nil {
+
+		if options.OnlyValueEditable {
+			query.Add("onlyValueEditable", "true")
+		}
+
+		if options.OrderByName {
+			query.Add("orderByName", "true")
+		}
+
+		if options.Query != "" {
+			query.Add("query", options.Query)
+		}
+
+		if options.IncludeValuesExist {
+			query.Add("includeValuesExist", "true")
+		}
+
+		if options.ExcludeParentAttributes {
+			query.Add("excludeParentAttributes", "true")
+		}
+
+		if options.IncludeChildren {
+			query.Add("includeChildren", "true")
+		}
+
+		if options.OrderByRequired {
+			query.Add("orderByRequired", "true")
+		}
+	}
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var attributes []*model.ObjectTypeAttributeScheme
+	res, err := i.c.Call(req, &attributes)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return attributes, res, nil
+}
+
+func (i *internalObjectTypeImpl) Position(ctx context.Context, workspaceID, objectTypeID string, payload *model.ObjectTypePositionPayloadScheme) (*model.ObjectTypeScheme, *model.ResponseScheme, error) {
+
+	if workspaceID == "" {
+		return nil, nil, model.ErrNoWorkspaceIDError
+	}
+
+	if objectTypeID == "" {
+		return nil, nil, model.ErrNoObjectTypeIDError
+	}
+
+	endpoint := fmt.Sprintf("jsm/assets/workspace/%v/v1/objecttype/%v/position", workspaceID, objectTypeID)
+
+	req, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	objectType := new(model.ObjectTypeScheme)
+	res, err := i.c.Call(req, objectType)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return objectType, res, nil
+}
diff --git a/jira/sm/api_client_impl.go b/jira/sm/api_client_impl.go
index fe5942a..90a70db 100644
--- a/jira/sm/api_client_impl.go
+++ b/jira/sm/api_client_impl.go
@@ -44,6 +44,7 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
 	client.Info = internal.NewInfoService(client, defaultServiceManagementVersion)
 	client.Knowledgebase = internal.NewKnowledgebaseService(client, defaultServiceManagementVersion)
 	client.Organization = internal.NewOrganizationService(client, defaultServiceManagementVersion)
+	client.WorkSpace = internal.NewWorkSpaceService(client, defaultServiceManagementVersion)
 
 	requestSubServices := &internal.ServiceRequestSubServices{
 		Approval:    internal.NewApprovalService(client, defaultServiceManagementVersion),
@@ -84,6 +85,7 @@ type Client struct {
 	Organization  *internal.OrganizationService
 	Request       *internal.RequestService
 	ServiceDesk   *internal.ServiceDeskService
+	WorkSpace     *internal.WorkSpaceService
 }
 
 func (c *Client) NewRequest(ctx context.Context, method, urlStr, type_ string, body interface{}) (*http.Request, error) {
diff --git a/jira/sm/internal/workspace_impl.go b/jira/sm/internal/workspace_impl.go
new file mode 100644
index 0000000..1475050
--- /dev/null
+++ b/jira/sm/internal/workspace_impl.go
@@ -0,0 +1,57 @@
+package internal
+
+import (
+	"context"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/sm"
+	"net/http"
+)
+
+func NewWorkSpaceService(client service.Connector, version string) *WorkSpaceService {
+
+	return &WorkSpaceService{
+		internalClient: &internalWorkSpaceImpl{c: client, version: version},
+	}
+}
+
+type WorkSpaceService struct {
+	internalClient sm.WorkSpaceConnector
+}
+
+// Gets retrieves workspace assets
+//
+// This endpoint is used to fetch the assets associated with a workspace.
+//
+// These assets may include knowledge base articles, request types, request fields, customer portals, queues, etc.
+//
+// GET /rest/servicedeskapi/assets/workspace
+//
+// https://docs.go-atlassian.io/jira-service-management/workspaces#get-workspaces
+func (w *WorkSpaceService) Gets(ctx context.Context) (*model.WorkSpacePageScheme, *model.ResponseScheme, error) {
+	return w.internalClient.Gets(ctx)
+}
+
+type internalWorkSpaceImpl struct {
+	c       service.Connector
+	version string
+}
+
+func (i *internalWorkSpaceImpl) Gets(ctx context.Context) (*model.WorkSpacePageScheme, *model.ResponseScheme, error) {
+
+	endpoint := "/rest/servicedeskapi/assets/workspace"
+
+	req, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	page := new(model.WorkSpacePageScheme)
+	res, err := i.c.Call(req, page)
+	if err != nil {
+		return nil, res, err
+	}
+
+	return page, res, nil
+
+}
diff --git a/pkg/infra/models/assets_aql.go b/pkg/infra/models/assets_aql.go
new file mode 100644
index 0000000..181faf3
--- /dev/null
+++ b/pkg/infra/models/assets_aql.go
@@ -0,0 +1,65 @@
+package models
+
+type AQLSearchParamsScheme struct {
+
+	// The query to determine which objects that should be fetched.
+	//
+	// E.g. objectType = "Computer". The empty AQL means all objects
+	Query string `query:"qlQuery,omitempty"`
+
+	// Which page to fetch when paginating through the response
+	Page int `query:"page,omitempty"`
+
+	// The amount of objects returned per page
+	ResultPerPage int `query:"resultPerPage,omitempty"`
+
+	// Should the objects attributes be included in the response.
+	//
+	// If this parameter is false only the information on the object will
+	//
+	// be returned and the object attributes will not be present
+	IncludeAttributes bool `query:"includeAttributes,omitempty"`
+
+	// How many levels of attributes should be included.
+	//
+	// E.g. consider an object A that has a reference to object B that has a reference to object C.
+	//
+	// If object A is included in the response and includeAttributesDeep=1 object A's reference to
+	//
+	// object B will be included in the attributes of object A but object B's reference to
+	//
+	// object C will not be included. However, if the includeAttributesDeep=2 then object B's
+	//
+	// reference to object C will be included in object B's attributes
+	IncludeAttributesDeep bool `query:"includeAttributesDeep,omitempty"`
+
+	// Should the response include the object type attribute definition
+	//
+	// for each attribute that is returned with the objects
+	IncludeTypeAttributes bool `query:"includeTypeAttributes,omitempty"`
+
+	// Include information about open Jira issues.
+	//
+	// Should each object have information if open tickets are connected to the object?
+	IncludeExtendedInfo bool `query:"includeExtendedInfo,omitempty"`
+}
+
+type ObjectPageScheme struct {
+	ObjectEntries         []*ObjectScheme              `json:"objectEntries"`
+	ObjectTypeAttributes  []*ObjectTypeAttributeScheme `json:"objectTypeAttributes"`
+	ObjectTypeID          string                       `json:"objectTypeId"`
+	ObjectTypeIsInherited bool                         `json:"objectTypeIsInherited"`
+	AbstractObjectType    bool                         `json:"abstractObjectType"`
+	TotalFilterCount      int                          `json:"totalFilterCount"`
+	StartIndex            int                          `json:"startIndex"`
+	ToIndex               int                          `json:"toIndex"`
+	PageObjectSize        int                          `json:"pageObjectSize"`
+	PageNumber            int                          `json:"pageNumber"`
+	OrderByTypeAttrId     int                          `json:"orderByTypeAttrId"`
+	OrderWay              string                       `json:"orderWay"`
+	QlQuery               string                       `json:"qlQuery"`
+	QlQuerySearchResult   bool                         `json:"qlQuerySearchResult"`
+	Iql                   string                       `json:"iql"`
+	IqlSearchResult       bool                         `json:"iqlSearchResult"`
+	ConversionPossible    bool                         `json:"conversionPossible"`
+}
diff --git a/pkg/infra/models/assets_icon.go b/pkg/infra/models/assets_icon.go
new file mode 100644
index 0000000..f33456e
--- /dev/null
+++ b/pkg/infra/models/assets_icon.go
@@ -0,0 +1,8 @@
+package models
+
+type IconScheme struct {
+	ID    string `json:"id,omitempty"`
+	Name  string `json:"name,omitempty"`
+	URL16 string `json:"url16,omitempty"`
+	URL48 string `json:"url48,omitempty"`
+}
diff --git a/pkg/infra/models/assets_object.go b/pkg/infra/models/assets_object.go
new file mode 100644
index 0000000..56b32fa
--- /dev/null
+++ b/pkg/infra/models/assets_object.go
@@ -0,0 +1,251 @@
+package models
+
+type ObjectReferenceTypeInfoScheme struct {
+	ReferenceTypes            []*TypeReferenceScheme `json:"referenceTypes,omitempty"`
+	ObjectType                *ObjectTypeScheme      `json:"objectType,omitempty"`
+	NumberOfReferencedObjects int                    `json:"numberOfReferencedObjects,omitempty"`
+	OpenIssuesExists          bool                   `json:"openIssuesExists,omitempty"`
+}
+
+type TypeReferenceScheme struct {
+	WorkspaceID    string `json:"workspaceId,omitempty"`
+	GlobalID       string `json:"globalId,omitempty"`
+	ID             string `json:"id,omitempty"`
+	Name           string `json:"name,omitempty"`
+	Description    string `json:"description,omitempty"`
+	Color          string `json:"color,omitempty"`
+	URL16          string `json:"url16,omitempty"`
+	Removable      bool   `json:"removable,omitempty"`
+	ObjectSchemaID string `json:"objectSchemaId,omitempty"`
+}
+
+type ObjectHistoryScheme struct {
+	Actor             *ObjectHistoryActorScheme `json:"actor,omitempty"`
+	ID                string                    `json:"id,omitempty"`
+	AffectedAttribute string                    `json:"affectedAttribute,omitempty"`
+	OldValue          string                    `json:"oldValue,omitempty"`
+	NewValue          string                    `json:"newValue,omitempty"`
+	Type              int                       `json:"type,omitempty"`
+	Created           string                    `json:"created,omitempty"`
+	ObjectID          string                    `json:"objectId,omitempty"`
+}
+
+type ObjectHistoryActorScheme struct {
+	AvatarUrl       string `json:"avatarUrl,omitempty"`
+	DisplayName     string `json:"displayName,omitempty"`
+	Name            string `json:"name,omitempty"`
+	Key             string `json:"key,omitempty"`
+	EmailAddress    string `json:"emailAddress,omitempty"`
+	Html            string `json:"html,omitempty"`
+	RenderedLink    string `json:"renderedLink,omitempty"`
+	IsDeleted       bool   `json:"isDeleted,omitempty"`
+	LastSeenVersion string `json:"lastSeenVersion,omitempty"`
+	Self            string `json:"self,omitempty"`
+}
+
+type ObjectPayloadScheme struct {
+	ObjectTypeID string                          `json:"objectTypeId,omitempty"`
+	AvatarUUID   string                          `json:"avatarUUID,omitempty"`
+	HasAvatar    bool                            `json:"hasAvatar,omitempty"`
+	Attributes   []*ObjectPayloadAttributeScheme `json:"attributes,omitempty"`
+}
+
+type ObjectPayloadAttributeScheme struct {
+	ObjectTypeAttributeID string                               `json:"objectTypeAttributeId,omitempty"`
+	ObjectAttributeValues []*ObjectPayloadAttributeValueScheme `json:"objectAttributeValues,omitempty"`
+}
+
+type ObjectPayloadAttributeValueScheme struct {
+	Value string `json:"value,omitempty"`
+}
+
+type ObjectScheme struct {
+	WorkspaceId string                   `json:"workspaceId,omitempty"`
+	GlobalId    string                   `json:"globalId,omitempty"`
+	ID          string                   `json:"id,omitempty"`
+	Label       string                   `json:"label,omitempty"`
+	ObjectKey   string                   `json:"objectKey,omitempty"`
+	Avatar      *ObjectAvatarScheme      `json:"avatar,omitempty"`
+	ObjectType  *ObjectTypeScheme        `json:"objectType,omitempty"`
+	Created     string                   `json:"created,omitempty"`
+	Updated     string                   `json:"updated,omitempty"`
+	HasAvatar   bool                     `json:"hasAvatar,omitempty"`
+	Timestamp   int                      `json:"timestamp,omitempty"`
+	Attributes  []*ObjectAttributeScheme `json:"attributes"`
+	Links       *ObjectLinksScheme       `json:"_links,omitempty"`
+}
+
+type ObjectAvatarScheme struct {
+	WorkspaceId string `json:"workspaceId,omitempty"`
+	GlobalId    string `json:"globalId,omitempty"`
+	ID          string `json:"id,omitempty"`
+	AvatarUUID  string `json:"avatarUUID,omitempty"`
+	Url16       string `json:"url16,omitempty"`
+	Url48       string `json:"url48,omitempty"`
+	Url72       string `json:"url72,omitempty"`
+	Url144      string `json:"url144,omitempty"`
+	Url288      string `json:"url288,omitempty"`
+	ObjectId    string `json:"objectId,omitempty"`
+}
+
+type ObjectLinksScheme struct {
+	Self string `json:"self,omitempty"`
+}
+
+type ObjectAttributeScheme struct {
+	WorkspaceId           string                                 `json:"workspaceId,omitempty"`
+	GlobalId              string                                 `json:"globalId,omitempty"`
+	ID                    string                                 `json:"id,omitempty"`
+	ObjectTypeAttribute   *ObjectTypeAttributeScheme             `json:"objectTypeAttribute,omitempty"`
+	ObjectTypeAttributeId string                                 `json:"objectTypeAttributeId,omitempty"`
+	ObjectAttributeValues []*ObjectTypeAssetAttributeValueScheme `json:"objectAttributeValues,omitempty"`
+}
+
+type ObjectTypeAttributeScheme struct {
+	WorkspaceId             string                                       `json:"workspaceId,omitempty"`
+	GlobalId                string                                       `json:"globalId,omitempty"`
+	ID                      string                                       `json:"id,omitempty"`
+	ObjectType              *ObjectTypeScheme                            `json:"objectType,omitempty"`
+	Name                    string                                       `json:"name,omitempty"`
+	Label                   bool                                         `json:"label,omitempty"`
+	Type                    int                                          `json:"type,omitempty"`
+	Description             string                                       `json:"description,omitempty"`
+	DefaultType             *ObjectTypeAssetAttributeDefaultTypeScheme   `json:"defaultType,omitempty"`
+	TypeValue               string                                       `json:"typeValue,omitempty"`
+	TypeValueMulti          []string                                     `json:"typeValueMulti,omitempty"`
+	AdditionalValue         string                                       `json:"additionalValue,omitempty"`
+	ReferenceType           *ObjectTypeAssetAttributeReferenceTypeScheme `json:"referenceType,omitempty"`
+	ReferenceObjectTypeId   string                                       `json:"referenceObjectTypeId,omitempty"`
+	ReferenceObjectType     *ObjectTypeScheme                            `json:"referenceObjectType,omitempty"`
+	Editable                bool                                         `json:"editable,omitempty"`
+	System                  bool                                         `json:"system,omitempty"`
+	Indexed                 bool                                         `json:"indexed,omitempty"`
+	Sortable                bool                                         `json:"sortable,omitempty"`
+	Summable                bool                                         `json:"summable,omitempty"`
+	MinimumCardinality      int                                          `json:"minimumCardinality,omitempty"`
+	MaximumCardinality      int                                          `json:"maximumCardinality,omitempty"`
+	Suffix                  string                                       `json:"suffix,omitempty"`
+	Removable               bool                                         `json:"removable,omitempty"`
+	ObjectAttributeExists   bool                                         `json:"objectAttributeExists,omitempty"`
+	Hidden                  bool                                         `json:"hidden,omitempty"`
+	IncludeChildObjectTypes bool                                         `json:"includeChildObjectTypes,omitempty"`
+	UniqueAttribute         bool                                         `json:"uniqueAttribute,omitempty"`
+	RegexValidation         string                                       `json:"regexValidation,omitempty"`
+	Iql                     string                                       `json:"iql,omitempty"`
+	QlQuery                 string                                       `json:"qlQuery,omitempty"`
+	Options                 string                                       `json:"options,omitempty"`
+	Position                int                                          `json:"position,omitempty"`
+}
+
+type ObjectTypeAssetAttributeDefaultTypeScheme struct {
+	ID   int    `json:"id,omitempty"`
+	Name string `json:"name,omitempty"`
+}
+
+type ObjectTypeAssetAttributeReferenceTypeScheme struct {
+	WorkspaceId string `json:"workspaceId,omitempty"`
+	GlobalId    string `json:"globalId,omitempty"`
+	Name        string `json:"name,omitempty"`
+}
+
+type ObjectTypeAssetAttributeValueScheme struct {
+	Value           string                                    `json:"value,omitempty"`
+	DisplayValue    string                                    `json:"displayValue,omitempty"`
+	SearchValue     string                                    `json:"searchValue,omitempty"`
+	Group           *ObjectTypeAssetAttributeValueGroupScheme `json:"group,omitempty"`
+	Status          *ObjectTypeAssetAttributeStatusScheme     `json:"status,omitempty"`
+	AdditionalValue string                                    `json:"additionalValue,omitempty"`
+}
+
+type ObjectTypeAssetAttributeValueGroupScheme struct {
+	AvatarUrl string `json:"avatarUrl,omitempty"`
+	Name      string `json:"name,omitempty"`
+}
+
+type ObjectTypeAssetAttributeStatusScheme struct {
+	ID       string `json:"id,omitempty"`
+	Name     string `json:"name,omitempty"`
+	Category int    `json:"category,omitempty"`
+}
+
+type ObjectListScheme struct {
+	ObjectEntries         []*ObjectScheme              `json:"objectEntries,omitempty"`
+	ObjectTypeAttributes  []*ObjectTypeAttributeScheme `json:"objectTypeAttributes,omitempty"`
+	ObjectTypeId          string                       `json:"objectTypeId,omitempty"`
+	ObjectTypeIsInherited bool                         `json:"objectTypeIsInherited,omitempty"`
+	AbstractObjectType    bool                         `json:"abstractObjectType,omitempty"`
+	TotalFilterCount      int                          `json:"totalFilterCount,omitempty"`
+	StartIndex            int                          `json:"startIndex,omitempty"`
+	ToIndex               int                          `json:"toIndex,omitempty"`
+	PageObjectSize        int                          `json:"pageObjectSize,omitempty"`
+	PageNumber            int                          `json:"pageNumber,omitempty"`
+	OrderByTypeAttrId     int                          `json:"orderByTypeAttrId,omitempty"`
+	OrderWay              string                       `json:"orderWay,omitempty"`
+	QlQuery               string                       `json:"qlQuery,omitempty"`
+	QlQuerySearchResult   bool                         `json:"qlQuerySearchResult,omitempty"`
+	Iql                   string                       `json:"iql,omitempty"`
+	IqlSearchResult       bool                         `json:"iqlSearchResult,omitempty"`
+	ConversionPossible    bool                         `json:"conversionPossible,omitempty"`
+}
+
+type ObjectListResultScheme struct {
+	StartAt              int                          `json:"startAt,omitempty"`
+	MaxResults           int                          `json:"maxResults,omitempty"`
+	Total                int                          `json:"total,omitempty"`
+	IsLast               bool                         `json:"isLast,omitempty"`
+	Values               []*ObjectScheme              `json:"values,omitempty"`
+	ObjectTypeAttributes []*ObjectTypeAttributeScheme `json:"objectTypeAttributes,omitempty"`
+}
+
+type ObjectSearchParamsScheme struct {
+
+	// The AQL that will fetch the objects.
+	//
+	// The object type parameter will be appended implicitly to this AQL
+	Query string `json:"qlQuery,omitempty"`
+
+	// Required if qlQuery is not set.
+	//
+	// Deprecated. Use Query instead.
+	Iql          string `json:"iql,omitempty"`
+	ObjectTypeID string `json:"objectTypeId,omitempty"`
+
+	// The requested page to be loaded for a paginated result.
+	//
+	// The default value is page = 1
+	Page int `json:"page,omitempty"`
+
+	// How many objects should be returned in the request.
+	//
+	// It is used with page attribute for pagination.
+	ResultPerPage int `json:"resultsPerPage,omitempty"`
+
+	// Which attribute should be used to order by.
+	//
+	// The preferred way is to use an order by in qlQuery and not pass this argument.
+	OrderByTypeAttributeID int `json:"orderByTypeAttrId,omitempty"`
+
+	// Sort objects in ascending order or descending order based on the attribute identified by orderByTypeAttrId.
+	//
+	// 1 mean ascending all other values mean descending.
+	//
+	// The preferred way is to not supply the asc parameter and use an order by in qlQuery instead.
+	Asc int `json:"asc,omitempty"`
+
+	// Identifies an object that should be included in the result.
+	//
+	// The page will be calculated accordingly to include the object specified in the result set
+	ObjectID string `json:"objectId,omitempty"`
+
+	ObjectSchemaID string `json:"objectSchemaId,omitempty"`
+
+	// Should attribute values be included in the response.
+	IncludeAttributes bool `json:"includeAttributes,omitempty"`
+
+	// Identifies attributes to be displayed
+	AttributesToDisplay *AttributesToDisplayScheme `json:"attributesToDisplay,omitempty"`
+}
+
+type AttributesToDisplayScheme struct {
+	AttributesToDisplayIds []int `json:"attributesToDisplayIds,omitempty"`
+}
diff --git a/pkg/infra/models/assets_object_schema.go b/pkg/infra/models/assets_object_schema.go
new file mode 100644
index 0000000..16e4238
--- /dev/null
+++ b/pkg/infra/models/assets_object_schema.go
@@ -0,0 +1,45 @@
+package models
+
+type ObjectSchemaPageScheme struct {
+	StartAt    int                   `json:"startAt,omitempty"`
+	MaxResults int                   `json:"maxResults,omitempty"`
+	Total      int                   `json:"total,omitempty"`
+	Values     []*ObjectSchemaScheme `json:"values,omitempty"`
+}
+
+type ObjectSchemaScheme struct {
+	WorkspaceId     string `json:"workspaceId,omitempty"`
+	GlobalId        string `json:"globalId,omitempty"`
+	Id              string `json:"id,omitempty"`
+	Name            string `json:"name,omitempty"`
+	ObjectSchemaKey string `json:"objectSchemaKey,omitempty"`
+	Description     string `json:"description,omitempty"`
+	Status          string `json:"status,omitempty"`
+	Created         string `json:"created,omitempty"`
+	Updated         string `json:"updated,omitempty"`
+	ObjectCount     int    `json:"objectCount,omitempty"`
+	ObjectTypeCount int    `json:"objectTypeCount,omitempty"`
+	CanManage       bool   `json:"canManage,omitempty"`
+}
+
+type ObjectSchemaPayloadScheme struct {
+	Name            string `json:"name,omitempty"`
+	ObjectSchemaKey string `json:"objectSchemaKey,omitempty"`
+	Description     string `json:"description,omitempty"`
+}
+
+type ObjectSchemaAttributesParamsScheme struct {
+
+	// OnlyValueEditable return only values that are associated with values that can be edited
+	OnlyValueEditable bool
+
+	// Extended include the object type with each object type attribute
+	Extended bool
+
+	// Query it's a query that will be used to filter object type attributes by their name
+	Query string
+}
+
+type ObjectSchemaTypePageScheme struct {
+	Entries []*ObjectTypeScheme `json:"entries,omitempty"`
+}
diff --git a/pkg/infra/models/assets_object_type.go b/pkg/infra/models/assets_object_type.go
new file mode 100644
index 0000000..95da70a
--- /dev/null
+++ b/pkg/infra/models/assets_object_type.go
@@ -0,0 +1,44 @@
+package models
+
+type ObjectTypePositionPayloadScheme struct {
+	ToObjectTypeId string `json:"toObjectTypeId,omitempty"`
+	Position       int    `json:"position,omitempty"`
+}
+
+type ObjectTypeScheme struct {
+	WorkspaceId               string      `json:"workspaceId,omitempty"`
+	GlobalId                  string      `json:"globalId,omitempty"`
+	Id                        string      `json:"id,omitempty"`
+	Name                      string      `json:"name,omitempty"`
+	Description               string      `json:"description,omitempty"`
+	Icon                      *IconScheme `json:"icon,omitempty"`
+	Position                  int         `json:"position,omitempty"`
+	Created                   string      `json:"created,omitempty"`
+	Updated                   string      `json:"updated,omitempty"`
+	ObjectCount               int         `json:"objectCount,omitempty"`
+	ParentObjectTypeId        string      `json:"parentObjectTypeId,omitempty"`
+	ObjectSchemaId            string      `json:"objectSchemaId,omitempty"`
+	Inherited                 bool        `json:"inherited,omitempty"`
+	AbstractObjectType        bool        `json:"abstractObjectType,omitempty"`
+	ParentObjectTypeInherited bool        `json:"parentObjectTypeInherited,omitempty"`
+}
+
+type ObjectTypePayloadScheme struct {
+	Name               string `json:"name,omitempty"`
+	Description        string `json:"description,omitempty"`
+	IconId             string `json:"iconId,omitempty"`
+	ObjectSchemaId     string `json:"objectSchemaId,omitempty"`
+	ParentObjectTypeId string `json:"parentObjectTypeId,omitempty"`
+	Inherited          bool   `json:"inherited,omitempty"`
+	AbstractObjectType bool   `json:"abstractObjectType,omitempty"`
+}
+
+type ObjectTypeAttributesParamsScheme struct {
+	OnlyValueEditable       bool
+	OrderByName             bool
+	Query                   string
+	IncludeValuesExist      bool
+	ExcludeParentAttributes bool
+	IncludeChildren         bool
+	OrderByRequired         bool
+}
diff --git a/pkg/infra/models/assets_ticket.go b/pkg/infra/models/assets_ticket.go
new file mode 100644
index 0000000..8e6c978
--- /dev/null
+++ b/pkg/infra/models/assets_ticket.go
@@ -0,0 +1,37 @@
+package models
+
+type TicketPageScheme struct {
+	Tickets         []*TicketScheme `json:"tickets,omitempty"`
+	AllTicketsQuery string          `json:"allTicketsQuery,omitempty"`
+}
+
+type TicketScheme struct {
+	WorkspaceId string                `json:"workspaceId,omitempty"`
+	GlobalId    string                `json:"globalId,omitempty"`
+	Key         string                `json:"key,omitempty"`
+	Id          string                `json:"id,omitempty"`
+	Reporter    string                `json:"reporter,omitempty"`
+	Created     string                `json:"created,omitempty"`
+	Updated     string                `json:"updated,omitempty"`
+	Title       string                `json:"title,omitempty"`
+	Status      *TicketStatusScheme   `json:"status,omitempty"`
+	Type        *TicketTypeScheme     `json:"type,omitempty"`
+	Priority    *TicketPriorityScheme `json:"priority,omitempty"`
+}
+
+type TicketStatusScheme struct {
+	Name        string `json:"name,omitempty"`
+	Description string `json:"description,omitempty"`
+	ColorName   string `json:"colorName,omitempty"`
+}
+
+type TicketTypeScheme struct {
+	Name        string `json:"name,omitempty"`
+	Description string `json:"description,omitempty"`
+	IconUrl     string `json:"iconUrl,omitempty"`
+}
+
+type TicketPriorityScheme struct {
+	Name    string `json:"name,omitempty"`
+	IconUrl string `json:"iconUrl,omitempty"`
+}
diff --git a/pkg/infra/models/errors.go b/pkg/infra/models/errors.go
index 018d286..7055453 100644
--- a/pkg/infra/models/errors.go
+++ b/pkg/infra/models/errors.go
@@ -131,34 +131,39 @@ var (
 	ErrNoIssueTypeSchemeIDError            = errors.New("jira: no issue type scheme id set")
 	ErrNoTaskIDError                       = errors.New("atlassian: no task id set")
 	ErrNoApprovalIDError                   = errors.New("jira: no approval id set")
-
-	ErrInvalidStatusCodeError = errors.New("client: invalid http response status, please refer the response.body for more details")
-	ErrNotFound               = errors.New("client: no atlassian resource found")
-	ErrUnauthorized           = errors.New("client: atlassian insufficient permissions")
-	ErrInternalError          = errors.New("client: atlassian internal error")
-	ErrBadRequestError        = errors.New("client: atlassian invalid payload")
-	ErrNoSiteError            = errors.New("client: no atlassian site set")
-
-	ErrNilPayloadError             = errors.New("client: please provide the necessary payload struct")
-	ErrNonPayloadPointerError      = errors.New("client: please provide a valid payload struct pointer (&)")
-	ErrNoFieldInformationError     = errors.New("custom-field: please provide a buffer with a valid fields object")
-	ErrNoCustomFieldUnmarshalError = errors.New("custom-field: no valid json provided")
-	ErrNoMultiSelectTypeError      = errors.New("custom-field: no multiselect type found")
-	ErrNoUrlTypeError              = errors.New("custom-field: no url type set")
-	ErrNoTextTypeError             = errors.New("custom-field: no text type set")
-	ErrNoDateTimeTypeError         = errors.New("custom-field: no date-time type set")
-	ErrNoDateTypeError             = errors.New("custom-field: no date type set")
-	ErrNoSelectTypeError           = errors.New("custom-field: no select type set")
-	ErrNoButtonTypeError           = errors.New("custom-field: no button type set")
-	ErrNoUserTypeError             = errors.New("custom-field: no user type set")
-	ErrNoMultiUserTypeError        = errors.New("custom-field: no multi-user type set")
-	ErrNoCheckBoxTypeError         = errors.New("custom-field: no check-box type set")
-	ErrNoCascadingParentError      = errors.New("custom-field: no cascading parent value set")
-	ErrNoCascadingChildError       = errors.New("custom-field: no cascading child value set")
-	ErrNoAttachmentIdsError        = errors.New("sm: no attachment id's set")
-	ErrNoLabelsError               = errors.New("sm: no label names set")
-	ErrNoComponentsError           = errors.New("sm: no components set")
-
-	ErrNoCreateIssuesError = errors.New("jira: no issues payload set")
-	ErrNoIssueSchemeError  = errors.New("jira: no issue instance set")
+	ErrInvalidStatusCodeError              = errors.New("client: invalid http response status, please refer the response.body for more details")
+	ErrNotFound                            = errors.New("client: no atlassian resource found")
+	ErrUnauthorized                        = errors.New("client: atlassian insufficient permissions")
+	ErrInternalError                       = errors.New("client: atlassian internal error")
+	ErrBadRequestError                     = errors.New("client: atlassian invalid payload")
+	ErrNilPayloadError                     = errors.New("client: please provide the necessary payload struct")
+	ErrNonPayloadPointerError              = errors.New("client: please provide a valid payload struct pointer (&)")
+	ErrNoFieldInformationError             = errors.New("custom-field: please provide a buffer with a valid fields object")
+	ErrNoCustomFieldUnmarshalError         = errors.New("custom-field: no valid json provided")
+	ErrNoMultiSelectTypeError              = errors.New("custom-field: no multiselect type found")
+	ErrNoAssetTypeError                    = errors.New("custom-field: no asset type found")
+	ErrNoUrlTypeError                      = errors.New("custom-field: no url type set")
+	ErrNoTextTypeError                     = errors.New("custom-field: no text type set")
+	ErrNoDateTimeTypeError                 = errors.New("custom-field: no date-time type set")
+	ErrNoDateTypeError                     = errors.New("custom-field: no date type set")
+	ErrNoSelectTypeError                   = errors.New("custom-field: no select type set")
+	ErrNoButtonTypeError                   = errors.New("custom-field: no button type set")
+	ErrNoUserTypeError                     = errors.New("custom-field: no user type set")
+	ErrNoMultiUserTypeError                = errors.New("custom-field: no multi-user type set")
+	ErrNoCheckBoxTypeError                 = errors.New("custom-field: no check-box type set")
+	ErrNoCascadingParentError              = errors.New("custom-field: no cascading parent value set")
+	ErrNoCascadingChildError               = errors.New("custom-field: no cascading child value set")
+	ErrNoAttachmentIdsError                = errors.New("sm: no attachment id's set")
+	ErrNoLabelsError                       = errors.New("sm: no label names set")
+	ErrNoComponentsError                   = errors.New("sm: no components set")
+	ErrNoWorkspaceIDError                  = errors.New("assets: no workspace id set")
+	ErrNoAqlQueryError                     = errors.New("assets: no aql query id set")
+	ErrNoIconIDError                       = errors.New("assets: no icon id set")
+	ErrNoObjectIDError                     = errors.New("assets: no object id set")
+	ErrNoObjectSchemaIDError               = errors.New("assets: no object schema id set")
+	ErrNoObjectTypeIDError                 = errors.New("assets: no object type id set")
+	ErrNoObjectTypeAttributeIDError        = errors.New("assets: no object type attribute id set")
+	ErrNoSiteError                         = errors.New("client: no atlassian site set")
+	ErrNoCreateIssuesError                 = errors.New("jira: no issues payload set")
+	ErrNoIssueSchemeError                  = errors.New("jira: no issue instance set")
 )
diff --git a/pkg/infra/models/jira_field_context_option.go b/pkg/infra/models/jira_field_context_option.go
index 58a3425..539e230 100644
--- a/pkg/infra/models/jira_field_context_option.go
+++ b/pkg/infra/models/jira_field_context_option.go
@@ -1,5 +1,11 @@
 package models
 
+type CustomFieldAssetScheme struct {
+	WorkspaceId string `json:"workspaceId,omitempty"`
+	Id          string `json:"id,omitempty"`
+	ObjectId    string `json:"objectId,omitempty"`
+}
+
 type CustomFieldContextOptionPageScheme struct {
 	Self       string                            `json:"self,omitempty"`
 	NextPage   string                            `json:"nextPage,omitempty"`
diff --git a/pkg/infra/models/jira_issue_custom_fields.go b/pkg/infra/models/jira_issue_custom_fields.go
index 047abdf..751fdc8 100644
--- a/pkg/infra/models/jira_issue_custom_fields.go
+++ b/pkg/infra/models/jira_issue_custom_fields.go
@@ -421,3 +421,41 @@ func ParseSelectCustomField(buffer bytes.Buffer, customField string) (*CustomFie
 
 	return cascading, nil
 }
+
+func ParseAssetCustomField(buffer bytes.Buffer, customField string) ([]*CustomFieldAssetScheme, error) {
+
+	raw, err := marshmallow.Unmarshal(buffer.Bytes(), &struct{}{})
+	if err != nil {
+		return nil, ErrNoCustomFieldUnmarshalError
+	}
+
+	fields, containsFields := raw["fields"]
+	if !containsFields {
+		return nil, ErrNoFieldInformationError
+	}
+
+	customFields := fields.(map[string]interface{})
+	var records []*CustomFieldAssetScheme
+
+	switch options := customFields[customField].(type) {
+	case []interface{}:
+
+		for _, option := range options {
+
+			record := &CustomFieldAssetScheme{
+				WorkspaceId: option.(map[string]interface{})["workspaceId"].(string),
+				Id:          option.(map[string]interface{})["id"].(string),
+				ObjectId:    option.(map[string]interface{})["objectId"].(string),
+			}
+
+			records = append(records, record)
+		}
+
+	case nil:
+		return nil, nil
+	default:
+		return nil, ErrNoAssetTypeError
+	}
+
+	return records, nil
+}
diff --git a/pkg/infra/models/sm_workspace.go b/pkg/infra/models/sm_workspace.go
new file mode 100644
index 0000000..726b310
--- /dev/null
+++ b/pkg/infra/models/sm_workspace.go
@@ -0,0 +1,20 @@
+package models
+
+type WorkSpacePageScheme struct {
+	Size       int                       `json:"size,omitempty"`
+	Start      int                       `json:"start,omitempty"`
+	Limit      int                       `json:"limit,omitempty"`
+	IsLastPage bool                      `json:"isLastPage,omitempty"`
+	Links      *WorkSpaceLinksPageScheme `json:"_links,omitempty"`
+	Values     []*WorkSpaceScheme        `json:"values,omitempty"`
+}
+
+type WorkSpaceLinksPageScheme struct {
+	Self    string `json:"self,omitempty"`
+	Base    string `json:"base,omitempty"`
+	Context string `json:"context,omitempty"`
+}
+
+type WorkSpaceScheme struct {
+	WorkspaceId string `json:"workspaceId,omitempty"`
+}
diff --git a/service/assets/aql.go b/service/assets/aql.go
new file mode 100644
index 0000000..9ec3dee
--- /dev/null
+++ b/service/assets/aql.go
@@ -0,0 +1,20 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// AQLAssetConnector represents the assets AQL search endpoints.
+// Use it to execute AQL searches.
+type AQLAssetConnector interface {
+
+	// Filter search objects based on Assets Query Language (AQL)
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/aql/objects
+	//
+	// Deprecated. Please use Object.Filter() instead.
+	//
+	// https://docs.go-atlassian.io/jira-assets/aql#filter-objects
+	Filter(ctx context.Context, workspaceID string, parameters *models.AQLSearchParamsScheme) (*models.ObjectListScheme, *models.ResponseScheme, error)
+}
diff --git a/service/assets/icon.go b/service/assets/icon.go
new file mode 100644
index 0000000..f4157d6
--- /dev/null
+++ b/service/assets/icon.go
@@ -0,0 +1,25 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// IconConnector represents the assets icons endpoints.
+// Use it to search and get asset icons.
+type IconConnector interface {
+
+	// Get loads a single asset icon by id.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/icon/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/icons#get-icon
+	Get(ctx context.Context, workspaceID, iconID string) (*models.IconScheme, *models.ResponseScheme, error)
+
+	// Global returns all global icons i.e. icons not associated with a particular object schema.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/icon/global
+	//
+	// https://docs.go-atlassian.io/jira-assets/icons#get-global-icons
+	Global(ctx context.Context, workspaceID string) ([]*models.IconScheme, *models.ResponseScheme, error)
+}
diff --git a/service/assets/object.go b/service/assets/object.go
new file mode 100644
index 0000000..8eb2f8d
--- /dev/null
+++ b/service/assets/object.go
@@ -0,0 +1,83 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// ObjectConnector represents the Assets objects.
+// Use it to search, get, create, delete, and change objects.
+type ObjectConnector interface {
+
+	// Get loads one object.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#get-object-by-id
+	Get(ctx context.Context, workspaceID, objectID string) (*models.ObjectScheme, *models.ResponseScheme, error)
+
+	// Update updates an existing object in Assets.
+	//
+	// PUT /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#update-object-by-id
+	Update(ctx context.Context, workspaceID, objectID string, payload *models.ObjectPayloadScheme) (*models.ObjectScheme, *models.ResponseScheme, error)
+
+	// Delete deletes the referenced object
+	//
+	// DELETE /jsm/assets/workspace/{workspaceId}/v1/object/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#delete-object-by-id
+	Delete(ctx context.Context, workspaceID, objectID string) (*models.ResponseScheme, error)
+
+	// Attributes list all attributes for the given object.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/attributes
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#get-object-attributes
+	Attributes(ctx context.Context, workspaceID, objectID string) ([]*models.ObjectAttributeScheme, *models.ResponseScheme, error)
+
+	// History retrieves the history entries for this object.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/history
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#get-object-changelogs
+	History(ctx context.Context, workspaceID, objectID string, ascOrder bool) ([]*models.ObjectHistoryScheme, *models.ResponseScheme, error)
+
+	// References finds all references for an object.
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/object/{id}/referenceinfo
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#get-object-references
+	References(ctx context.Context, workspaceID, objectID string) ([]*models.ObjectReferenceTypeInfoScheme, *models.ResponseScheme, error)
+
+	// Create creates a new object in Assets.
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/object/create
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#create-object
+	Create(ctx context.Context, workspaceID string, payload *models.ObjectPayloadScheme) (*models.ObjectScheme, *models.ResponseScheme, error)
+
+	// Relation returns the relation between Jira issues and Assets objects
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objectconnectedtickets/{objectId}/tickets
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#get-object-tickets
+	Relation(ctx context.Context, workspaceID, objectID string) (*models.TicketPageScheme, *models.ResponseScheme, error)
+
+	// Filter fetch Objects by AQL.
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/object/aql
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#filter-objects
+	Filter(ctx context.Context, workspaceID, aql string, attributes bool, startAt, maxResults int) (*models.ObjectListResultScheme, *models.ResponseScheme, error)
+
+	// Search retrieve a list of objects based on an AQL.
+	//
+	// Note that the preferred endpoint is /aql
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/object/navlist/aql
+	//
+	// https://docs.go-atlassian.io/jira-assets/object#search-objects
+	Search(ctx context.Context, workspaceID string, payload *models.ObjectSearchParamsScheme) (*models.ObjectListScheme, *models.ResponseScheme, error)
+}
diff --git a/service/assets/object_schema.go b/service/assets/object_schema.go
new file mode 100644
index 0000000..c4e4a49
--- /dev/null
+++ b/service/assets/object_schema.go
@@ -0,0 +1,64 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// ObjectSchemaConnector represents the Assets object schemes.
+// Use it to search, get, create, delete, and change schemes.
+type ObjectSchemaConnector interface {
+
+	// List returns all the object schemas available on Assets
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/list
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-list
+	List(ctx context.Context, workspaceID string) (*models.ObjectSchemaPageScheme, *models.ResponseScheme, error)
+
+	// Create creates a new object schema
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/objectschema/create
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#create-object-schema
+	Create(ctx context.Context, workspaceID string, payload *models.ObjectSchemaPayloadScheme) (*models.ObjectSchemaScheme,
+		*models.ResponseScheme, error)
+
+	// Get returns an object schema by ID
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema
+	Get(ctx context.Context, workspaceID, objectSchemaID string) (*models.ObjectSchemaScheme, *models.ResponseScheme, error)
+
+	// Update updates an object schema
+	//
+	// PUT /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#update-object-schema
+	Update(ctx context.Context, workspaceID, objectSchemaID string, payload *models.ObjectSchemaPayloadScheme) (
+		*models.ObjectSchemaScheme, *models.ResponseScheme, error)
+
+	// Delete deletes a schema
+	//
+	// DELETE /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#delete-object-schema
+	Delete(ctx context.Context, workspaceID, objectSchemaID string) (*models.ObjectSchemaScheme, *models.ResponseScheme, error)
+
+	// Attributes finds all object type attributes for this object schema
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}/attributes
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-attributes
+	Attributes(ctx context.Context, workspaceID, objectSchemaID string, options *models.ObjectSchemaAttributesParamsScheme) (
+		[]*models.ObjectTypeAttributeScheme, *models.ResponseScheme, error)
+
+	// ObjectTypes returns all object types for this object schema
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objectschema/{id}/objecttypes
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/schema#get-object-schema-types
+	ObjectTypes(ctx context.Context, workspaceID, objectSchemaID string, excludeAbstract bool) (
+		[]*models.ObjectTypeScheme, *models.ResponseScheme, error)
+}
diff --git a/service/assets/object_type.go b/service/assets/object_type.go
new file mode 100644
index 0000000..7a700da
--- /dev/null
+++ b/service/assets/object_type.go
@@ -0,0 +1,57 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// ObjectTypeConnector represents the Assets object types.
+// Use it to search, get, create, delete, and change types.
+type ObjectTypeConnector interface {
+
+	// Get finds an object type by id
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#get-object-type
+	Get(ctx context.Context, workspaceID, objectTypeID string) (*models.ObjectTypeScheme, *models.ResponseScheme, error)
+
+	// Update updates an existing object type
+	//
+	// PUT /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#update-object-type
+	Update(ctx context.Context, workspaceID, objectTypeID string, payload *models.ObjectTypePayloadScheme) (
+		*models.ObjectTypeScheme, *models.ResponseScheme, error)
+
+	// Create creates a new object type
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/objecttype/create
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#create-object-type
+	Create(ctx context.Context, workspaceID string, payload *models.ObjectTypePayloadScheme) (
+		*models.ObjectTypeScheme, *models.ResponseScheme, error)
+
+	// Delete deletes an object type
+	//
+	// DELETE /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#delete-object-type
+	Delete(ctx context.Context, workspaceID, objectTypeID string) (*models.ObjectTypeScheme, *models.ResponseScheme, error)
+
+	// Attributes finds all attributes for this object type
+	//
+	// GET /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}/attributes
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#get-object-type-attributes
+	Attributes(ctx context.Context, workspaceID, objectTypeID string, options *models.ObjectTypeAttributesParamsScheme) (
+		[]*models.ObjectTypeAttributeScheme, *models.ResponseScheme, error)
+
+	// Position changes the position of this object type
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/objecttype/{id}/position
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type#update-object-type-position
+	Position(ctx context.Context, workspaceID, objectTypeID string, payload *models.ObjectTypePositionPayloadScheme) (
+		*models.ObjectTypeScheme, *models.ResponseScheme, error)
+}
diff --git a/service/assets/object_type_attribute.go b/service/assets/object_type_attribute.go
new file mode 100644
index 0000000..9730602
--- /dev/null
+++ b/service/assets/object_type_attribute.go
@@ -0,0 +1,34 @@
+package assets
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// ObjectTypeAttributeConnector represents the Assets object type attributes.
+// Use it to search, get, create, delete, and change object type attributes.
+type ObjectTypeAttributeConnector interface {
+
+	// Create creates a new attribute on the given object type
+	//
+	// POST /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{objectTypeId}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type/attribute#create-object-type-attribute
+	Create(ctx context.Context, workspaceID, objectTypeID string, payload *models.ObjectTypeAttributeScheme) (
+		*models.ObjectTypeAttributeScheme, *models.ResponseScheme, error)
+
+	// Update updates an existing object type attribute
+	//
+	// PUT /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{objectTypeId}/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type/attribute#update-object-type-attribute
+	Update(ctx context.Context, workspaceID, objectTypeID, attributeID string, payload *models.ObjectTypeAttributeScheme) (
+		*models.ObjectTypeAttributeScheme, *models.ResponseScheme, error)
+
+	// Delete deletes an existing object type attribute
+	//
+	// DELETE /jsm/assets/workspace/{workspaceId}/v1/objecttypeattribute/{id}
+	//
+	// https://docs.go-atlassian.io/jira-assets/object/type/attribute#delete-object-type-attribute
+	Delete(ctx context.Context, workspaceID, attributeID string) (*models.ResponseScheme, error)
+}
diff --git a/service/sm/workspace.go b/service/sm/workspace.go
new file mode 100644
index 0000000..6f15d1d
--- /dev/null
+++ b/service/sm/workspace.go
@@ -0,0 +1,20 @@
+package sm
+
+import (
+	"context"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+type WorkSpaceConnector interface {
+
+	// Gets retrieves workspace assets
+	//
+	// This endpoint is used to fetch the assets associated with a workspace.
+	//
+	// These assets may include knowledge base articles, request types, request fields, customer portals, queues, etc.
+	//
+	// GET /rest/servicedeskapi/assets/workspace
+	//
+	// https://docs.go-atlassian.io/jira-service-management/workspaces#get-workspaces
+	Gets(ctx context.Context) (*models.WorkSpacePageScheme, *models.ResponseScheme, error)
+}


Test patch:
diff --git a/assets/api_client_impl_test.go b/assets/api_client_impl_test.go
new file mode 100644
index 0000000..b832285
--- /dev/null
+++ b/assets/api_client_impl_test.go
@@ -0,0 +1,522 @@
+package assets
+
+import (
+	"bytes"
+	"context"
+	"github.com/ctreminiom/go-atlassian/assets/internal"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service/common"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+	"testing"
+)
+
+func TestClient_Call(t *testing.T) {
+
+	expectedResponse := &http.Response{
+		StatusCode: http.StatusOK,
+		Body:       io.NopCloser(strings.NewReader("Hello, world!")),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	badRequestResponse := &http.Response{
+		StatusCode: http.StatusBadRequest,
+		Body:       io.NopCloser(strings.NewReader("Hello, world!")),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	internalServerResponse := &http.Response{
+		StatusCode: http.StatusInternalServerError,
+		Body:       io.NopCloser(strings.NewReader("Hello, world!")),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	unauthorizedResponse := &http.Response{
+		StatusCode: http.StatusUnauthorized,
+		Body:       io.NopCloser(strings.NewReader("Hello, world!")),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	notFoundResponse := &http.Response{
+		StatusCode: http.StatusNotFound,
+		Body:       io.NopCloser(strings.NewReader("Hello, world!")),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	type fields struct {
+		HTTP common.HttpClient
+		Site *url.URL
+		Auth common.Authentication
+	}
+	type args struct {
+		request   *http.Request
+		structure interface{}
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		want    *model.ResponseScheme
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			on: func(fields *fields) {
+
+				client := mocks.NewHttpClient(t)
+
+				client.On("Do", (*http.Request)(nil)).
+					Return(expectedResponse, nil)
+
+				fields.HTTP = client
+			},
+			args: args{
+				request:   nil,
+				structure: nil,
+			},
+			want: &model.ResponseScheme{
+				Response: expectedResponse,
+				Code:     http.StatusOK,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString("Hello, world!"),
+			},
+			wantErr: false,
+		},
+
+		{
+			name: "when the response status is a bad request",
+			on: func(fields *fields) {
+
+				client := mocks.NewHttpClient(t)
+
+				client.On("Do", (*http.Request)(nil)).
+					Return(badRequestResponse, nil)
+
+				fields.HTTP = client
+			},
+			args: args{
+				request:   nil,
+				structure: nil,
+			},
+			want: &model.ResponseScheme{
+				Response: badRequestResponse,
+				Code:     http.StatusBadRequest,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString("Hello, world!"),
+			},
+			wantErr: true,
+			Err:     model.ErrBadRequestError,
+		},
+
+		{
+			name: "when the response status is an internal service error",
+			on: func(fields *fields) {
+
+				client := mocks.NewHttpClient(t)
+
+				client.On("Do", (*http.Request)(nil)).
+					Return(internalServerResponse, nil)
+
+				fields.HTTP = client
+			},
+			args: args{
+				request:   nil,
+				structure: nil,
+			},
+			want: &model.ResponseScheme{
+				Response: internalServerResponse,
+				Code:     http.StatusInternalServerError,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString("Hello, world!"),
+			},
+			wantErr: true,
+			Err:     model.ErrInternalError,
+		},
+
+		{
+			name: "when the response status is a not found",
+			on: func(fields *fields) {
+
+				client := mocks.NewHttpClient(t)
+
+				client.On("Do", (*http.Request)(nil)).
+					Return(notFoundResponse, nil)
+
+				fields.HTTP = client
+			},
+			args: args{
+				request:   nil,
+				structure: nil,
+			},
+			want: &model.ResponseScheme{
+				Response: notFoundResponse,
+				Code:     http.StatusNotFound,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString("Hello, world!"),
+			},
+			wantErr: true,
+			Err:     model.ErrNotFound,
+		},
+
+		{
+			name: "when the response status is unauthorized",
+			on: func(fields *fields) {
+
+				client := mocks.NewHttpClient(t)
+
+				client.On("Do", (*http.Request)(nil)).
+					Return(unauthorizedResponse, nil)
+
+				fields.HTTP = client
+			},
+			args: args{
+				request:   nil,
+				structure: nil,
+			},
+			want: &model.ResponseScheme{
+				Response: unauthorizedResponse,
+				Code:     http.StatusUnauthorized,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString("Hello, world!"),
+			},
+			wantErr: true,
+			Err:     model.ErrUnauthorized,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			c := &Client{
+				HTTP: testCase.fields.HTTP,
+				Site: testCase.fields.Site,
+			}
+
+			got, err := c.Call(testCase.args.request, testCase.args.structure)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, got, testCase.want)
+			}
+
+		})
+	}
+}
+
+func TestClient_NewRequest(t *testing.T) {
+
+	authMocked := internal.NewAuthenticationService(nil)
+	authMocked.SetBasicAuth("mail", "token")
+	authMocked.SetUserAgent("firefox")
+
+	siteAsURL, err := url.Parse("https://ctreminiom.atlassian.net")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	requestMocked, err := http.NewRequestWithContext(context.TODO(),
+		http.MethodGet,
+		"https://ctreminiom.atlassian.net/rest/2/issue/attachment",
+		bytes.NewReader([]byte("Hello World")),
+	)
+
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	requestMocked.Header.Set("Accept", "application/json")
+	requestMocked.Header.Set("Content-Type", "application/json")
+
+	type fields struct {
+		HTTP common.HttpClient
+		Auth common.Authentication
+		Site *url.URL
+	}
+
+	type args struct {
+		ctx    context.Context
+		method string
+		urlStr string
+		type_  string
+		body   interface{}
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *http.Request
+		wantErr bool
+	}{
+		{
+			name: "when the parameters are correct",
+			fields: fields{
+				HTTP: http.DefaultClient,
+				Auth: authMocked,
+				Site: siteAsURL,
+			},
+			args: args{
+				ctx:    context.TODO(),
+				method: http.MethodGet,
+				urlStr: "rest/2/issue/attachment",
+				type_:  "",
+				body:   bytes.NewReader([]byte("Hello World")),
+			},
+			want:    requestMocked,
+			wantErr: false,
+		},
+
+		{
+			name: "when the url cannot be parsed",
+			fields: fields{
+				HTTP: http.DefaultClient,
+				Auth: internal.NewAuthenticationService(nil),
+				Site: siteAsURL,
+			},
+			args: args{
+				ctx:    context.TODO(),
+				method: http.MethodGet,
+				urlStr: " https://zhidao.baidu.com/special/view?id=49105a24626975510000&preview=1",
+				body:   bytes.NewReader([]byte("Hello World")),
+			},
+			want:    nil,
+			wantErr: true,
+		},
+
+		{
+			name: "when the request cannot be created",
+			fields: fields{
+				HTTP: http.DefaultClient,
+				Auth: internal.NewAuthenticationService(nil),
+				Site: siteAsURL,
+			},
+			args: args{
+				ctx:    nil,
+				method: http.MethodGet,
+				urlStr: "rest/2/issue/attachment",
+				body:   bytes.NewReader([]byte("Hello World")),
+			},
+			want:    requestMocked,
+			wantErr: true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			c := &Client{
+				HTTP: testCase.fields.HTTP,
+				Auth: testCase.fields.Auth,
+				Site: testCase.fields.Site,
+			}
+
+			got, err := c.NewRequest(
+				testCase.args.ctx,
+				testCase.args.method,
+				testCase.args.urlStr,
+				testCase.args.type_,
+				testCase.args.body,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				assert.NotEqual(t, got, nil)
+			}
+
+		})
+	}
+}
+
+func TestClient_processResponse(t *testing.T) {
+
+	expectedJsonResponse := `
+	{
+	  "id": 4,
+	  "self": "https://ctreminiom.atlassian.net/rest/agile/1.0/board/4",
+	  "name": "KP - Scrum",
+	  "type": "scrum"
+	}`
+
+	expectedResponse := &http.Response{
+		StatusCode: http.StatusOK,
+		Body:       io.NopCloser(strings.NewReader(expectedJsonResponse)),
+		Request: &http.Request{
+			Method: http.MethodGet,
+			URL:    &url.URL{},
+		},
+	}
+
+	type fields struct {
+		HTTP           common.HttpClient
+		Site           *url.URL
+		Authentication common.Authentication
+	}
+	type args struct {
+		response  *http.Response
+		structure interface{}
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *model.ResponseScheme
+		wantErr bool
+		Err     error
+	}{
+		{
+			name:   "when the parameters are correct",
+			fields: fields{},
+			args: args{
+				response:  expectedResponse,
+				structure: model.BoardScheme{},
+			},
+			want: &model.ResponseScheme{
+				Response: expectedResponse,
+				Code:     http.StatusOK,
+				Method:   http.MethodGet,
+				Bytes:    *bytes.NewBufferString(expectedJsonResponse),
+			},
+			wantErr: false,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			c := &Client{
+				HTTP: testCase.fields.HTTP,
+				Site: testCase.fields.Site,
+				Auth: testCase.fields.Authentication,
+			}
+
+			got, err := c.processResponse(testCase.args.response, testCase.args.structure)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+				assert.EqualError(t, err, testCase.Err.Error())
+
+			} else {
+				assert.NoError(t, err)
+				assert.NotEqual(t, got, nil)
+			}
+
+		})
+	}
+}
+
+func TestNew(t *testing.T) {
+
+	mockClient, err := New(http.DefaultClient, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	mockClient.Auth.SetBasicAuth("test", "test")
+	mockClient.Auth.SetUserAgent("aaa")
+
+	mockClientWithOutClient, err := New(nil, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	mockClientWithOutClient.Auth.SetBasicAuth("test", "test")
+	mockClientWithOutClient.Auth.SetUserAgent("aaa")
+
+	type args struct {
+		httpClient common.HttpClient
+		site       string
+	}
+
+	testCases := []struct {
+		name    string
+		args    args
+		want    *Client
+		wantErr bool
+		Err     error
+	}{
+
+		{
+			name: "when the parameters are correct",
+			args: args{
+				httpClient: http.DefaultClient,
+			},
+			want:    mockClient,
+			wantErr: false,
+		},
+
+		{
+			name: "when the http client is not provided",
+			args: args{
+				httpClient: nil,
+			},
+			want:    mockClientWithOutClient,
+			wantErr: false,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			gotClient, err := New(testCase.args.httpClient, testCase.args.site)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.Error(t, err)
+				assert.EqualError(t, err, testCase.Err.Error())
+
+			} else {
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotClient, nil)
+			}
+		})
+	}
+}
diff --git a/assets/internal/aql_impl_test.go b/assets/internal/aql_impl_test.go
new file mode 100644
index 0000000..5919a3d
--- /dev/null
+++ b/assets/internal/aql_impl_test.go
@@ -0,0 +1,135 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"testing"
+)
+
+func Test_internalAQLImpl_Filter(t *testing.T) {
+
+	payloadMocked := &model.AQLSearchParamsScheme{
+		Query:                 "Name LIKE Test",
+		Page:                  2,
+		ResultPerPage:         25,
+		IncludeAttributes:     true,
+		IncludeAttributesDeep: true,
+		IncludeTypeAttributes: true,
+		IncludeExtendedInfo:   true,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		payload     *model.AQLSearchParamsScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/aql/objects?includeAttributes=true&includeAttributesDeep=true&includeExtendedInfo=true&includeTypeAttributes=true&page=2&qlQuery=Name+LIKE+Test&resultPerPage=25",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectListScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/aql/objects?includeAttributes=true&includeAttributesDeep=true&includeExtendedInfo=true&includeTypeAttributes=true&page=2&qlQuery=Name+LIKE+Test&resultPerPage=25",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newAQLService := NewAQLService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newAQLService.Filter(testCase.args.ctx, testCase.args.workspaceID, testCase.args.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
diff --git a/assets/internal/authentication_impl_test.go b/assets/internal/authentication_impl_test.go
new file mode 100644
index 0000000..052f346
--- /dev/null
+++ b/assets/internal/authentication_impl_test.go
@@ -0,0 +1,454 @@
+package internal
+
+import (
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/common"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"reflect"
+	"testing"
+)
+
+func TestAuthenticationService_GetBasicAuth(t *testing.T) {
+
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		want   string
+		want1  string
+	}{
+		{
+			name: "when the basic auth is already set",
+			fields: fields{
+				c:     mocks.NewConnector(t),
+				mail:  "mail",
+				token: "token",
+			},
+			want:  "mail",
+			want1: "token",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+
+			got, got1 := a.GetBasicAuth()
+			if got != testCase.want {
+				t.Errorf("GetBasicAuth() got = %v, want %v", got, testCase.want)
+			}
+
+			if got1 != testCase.want1 {
+				t.Errorf("GetBasicAuth() got1 = %v, want %v", got1, testCase.want1)
+			}
+		})
+	}
+}
+
+func TestAuthenticationService_GetUserAgent(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		{
+			name: "when the user agent is already set",
+			fields: fields{
+				c:     mocks.NewConnector(t),
+				agent: "firefox-09",
+			},
+			want: "firefox-09",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+			if got := a.GetUserAgent(); got != testCase.want {
+				t.Errorf("GetUserAgent() = %v, want %v", got, testCase.want)
+			}
+		})
+	}
+}
+
+func TestAuthenticationService_HasBasicAuth(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		want   bool
+	}{
+		{
+			name: "when the params are correct",
+			fields: fields{
+				c:                 mocks.NewConnector(t),
+				basicAuthProvided: true,
+			},
+			want: true,
+		},
+	}
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+			if got := a.HasBasicAuth(); got != testCase.want {
+				t.Errorf("HasBasicAuth() = %v, want %v", got, testCase.want)
+			}
+		})
+	}
+}
+
+func TestAuthenticationService_HasUserAgent(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		want   bool
+	}{
+		{
+			name: "when the parameters are correct",
+			fields: fields{
+				userAgentProvided: true,
+			},
+			want: true,
+		},
+	}
+	for _, testCase := range testCases {
+
+		t.Run(testCase.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+
+			if got := a.HasUserAgent(); got != testCase.want {
+				t.Errorf("HasUserAgent() = %v, want %v", got, testCase.want)
+			}
+		})
+	}
+}
+
+func TestNewAuthenticationService(t *testing.T) {
+
+	clientMocked := mocks.NewConnector(t)
+
+	type args struct {
+		client service.Connector
+	}
+	testCases := []struct {
+		name string
+		args args
+		want common.Authentication
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				client: clientMocked,
+			},
+			want: NewAuthenticationService(clientMocked),
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			if got := NewAuthenticationService(testCase.args.client); !reflect.DeepEqual(got, testCase.want) {
+				t.Errorf("NewAuthenticationService() = %v, want %v", got, testCase.want)
+			}
+		})
+	}
+}
+
+func TestAuthenticationService_SetUserAgent(t *testing.T) {
+
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	type args struct {
+		agent string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		args   args
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{agent: "mozilla-9"},
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+
+			a.SetUserAgent(testCase.args.agent)
+		})
+	}
+}
+
+func TestAuthenticationService_SetBasicAuth(t *testing.T) {
+
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	type args struct {
+		mail  string
+		token string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		args   args
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				mail:  "example@example.com",
+				token: "token-sample",
+			},
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+
+			a.SetBasicAuth(testCase.args.mail, testCase.args.token)
+		})
+	}
+}
+
+func TestAuthenticationService_HasSetExperimentalFlag(t *testing.T) {
+
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	testCases := []struct {
+		name   string
+		fields fields
+		want   bool
+	}{
+
+		{
+			name:   "when the parameters are correct",
+			fields: fields{},
+			want:   false,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 testCase.fields.c,
+				basicAuthProvided: testCase.fields.basicAuthProvided,
+				mail:              testCase.fields.mail,
+				token:             testCase.fields.token,
+				userAgentProvided: testCase.fields.userAgentProvided,
+				agent:             testCase.fields.agent,
+			}
+			if got := a.HasSetExperimentalFlag(); got != testCase.want {
+				t.Errorf("HasSetExperimentalFlag() = %v, want %v", got, testCase.want)
+			}
+		})
+	}
+}
+
+func TestAuthenticationService_GetBearerToken(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		{
+			name: "when the parameters are correct",
+			fields: fields{
+				c:     mocks.NewConnector(t),
+				token: "token-sample",
+			},
+			want: "token-sample",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 tt.fields.c,
+				basicAuthProvided: tt.fields.basicAuthProvided,
+				mail:              tt.fields.mail,
+				token:             tt.fields.token,
+				userAgentProvided: tt.fields.userAgentProvided,
+				agent:             tt.fields.agent,
+			}
+			assert.Equalf(t, tt.want, a.GetBearerToken(), "GetBearerToken()")
+		})
+	}
+}
+
+func TestAuthenticationService_SetBearerToken(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	type args struct {
+		token string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+	}{
+		{
+			name: "when the parameters are correct",
+			fields: fields{
+				token: "token-sample",
+			},
+			args: args{
+				token: "token-sample",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 tt.fields.c,
+				basicAuthProvided: tt.fields.basicAuthProvided,
+				mail:              tt.fields.mail,
+				token:             tt.fields.token,
+				userAgentProvided: tt.fields.userAgentProvided,
+				agent:             tt.fields.agent,
+			}
+			a.SetBearerToken(tt.args.token)
+		})
+	}
+}
+
+func TestAuthenticationService_SetExperimentalFlag(t *testing.T) {
+	type fields struct {
+		c                 service.Connector
+		basicAuthProvided bool
+		mail              string
+		token             string
+		userAgentProvided bool
+		agent             string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+	}{
+		{
+			name: "when the parameters are correct",
+			fields: fields{
+				c:                 nil,
+				basicAuthProvided: false,
+				mail:              "",
+				token:             "",
+				userAgentProvided: false,
+				agent:             "",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			a := &AuthenticationService{
+				c:                 tt.fields.c,
+				basicAuthProvided: tt.fields.basicAuthProvided,
+				mail:              tt.fields.mail,
+				token:             tt.fields.token,
+				userAgentProvided: tt.fields.userAgentProvided,
+				agent:             tt.fields.agent,
+			}
+			a.SetExperimentalFlag()
+		})
+	}
+}
diff --git a/assets/internal/icon_impl_test.go b/assets/internal/icon_impl_test.go
new file mode 100644
index 0000000..4e2c7df
--- /dev/null
+++ b/assets/internal/icon_impl_test.go
@@ -0,0 +1,245 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"net/http"
+	"testing"
+)
+
+func Test_internalIconImpl_Get(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                 context.Context
+		workspaceID, iconID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				iconID:      "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/icon/1",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.IconScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				iconID:      "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/icon/1",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the icon id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoIconIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newService := NewIconService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newService.Get(testCase.args.ctx, testCase.args.workspaceID, testCase.args.iconID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalIconImpl_Global(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/icon/global",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/icon/global",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newIconService := NewIconService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newIconService.Global(testCase.args.ctx, testCase.args.workspaceID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
diff --git a/assets/internal/object_impl_test.go b/assets/internal/object_impl_test.go
new file mode 100644
index 0000000..d747bd0
--- /dev/null
+++ b/assets/internal/object_impl_test.go
@@ -0,0 +1,1282 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"net/http"
+	"testing"
+)
+
+func Test_internalObjectImpl_Get(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Get(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Delete(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					nil).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResponse, err := newObjectService.Delete(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Attributes(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/attributes",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/attributes",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Attributes(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_History(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+		ascOrder              bool
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+				ascOrder:    true,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/history?asc=true",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+				ascOrder:    true,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/history?asc=true",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.History(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID,
+				testCase.args.ascOrder)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_References(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/referenceinfo",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/1/referenceinfo",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.References(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Relation(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                   context.Context
+		workspaceID, objectID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectconnectedtickets/1/tickets",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.TicketPageScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "1",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectconnectedtickets/1/tickets",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Relation(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Update(t *testing.T) {
+
+	payloadMocked := &model.ObjectPayloadScheme{
+		ObjectTypeID: "23",
+		HasAvatar:    false,
+		Attributes: []*model.ObjectPayloadAttributeScheme{
+			{
+				ObjectTypeAttributeID: "265",
+				ObjectAttributeValues: []*model.ObjectPayloadAttributeValueScheme{
+					{
+						Value: "A placeholder value",
+					},
+				},
+			},
+		},
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		objectID    string
+		payload     *model.ObjectPayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "object-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/object-uuid-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				objectID:    "object-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/object-uuid-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Update(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectID,
+				testCase.args.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Create(t *testing.T) {
+
+	payloadMocked := &model.ObjectPayloadScheme{
+		ObjectTypeID: "23",
+		HasAvatar:    false,
+		Attributes: []*model.ObjectPayloadAttributeScheme{
+			{
+				ObjectTypeAttributeID: "135",
+				ObjectAttributeValues: []*model.ObjectPayloadAttributeValueScheme{
+					{
+						Value: "NY-1",
+					},
+				},
+			},
+			{
+				ObjectTypeAttributeID: "144",
+				ObjectAttributeValues: []*model.ObjectPayloadAttributeValueScheme{
+					{
+						Value: "99",
+					},
+				},
+			},
+		},
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		payload     *model.ObjectPayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Create(testCase.args.ctx, testCase.args.workspaceID, testCase.args.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Filter(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                 context.Context
+		workspaceID, aql    string
+		attributes          bool
+		startAt, maxResults int
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				aql:         "objectType = Office AND Name LIKE SYD",
+				attributes:  false,
+				startAt:     50,
+				maxResults:  50,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/aql?includeAttributes=false&maxResults=50&startAt=50",
+					"",
+					map[string]interface{}{"qlQuery": "objectType = Office AND Name LIKE SYD"}).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectListResultScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				aql:         "objectType = Office AND Name LIKE SYD",
+				attributes:  false,
+				startAt:     50,
+				maxResults:  50,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/aql?includeAttributes=false&maxResults=50&startAt=50",
+					"",
+					map[string]interface{}{"qlQuery": "objectType = Office AND Name LIKE SYD"}).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the aql query is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoAqlQueryError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Filter(testCase.args.ctx, testCase.args.workspaceID, testCase.args.aql,
+				testCase.args.attributes, testCase.args.startAt, testCase.args.maxResults)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectImpl_Search(t *testing.T) {
+
+	payloadMocked := &model.ObjectSearchParamsScheme{
+		Query:             "objectType = Office AND Name LIKE SYD",
+		ObjectTypeID:      "23",
+		Page:              1,
+		ResultPerPage:     25,
+		ObjectSchemaID:    "6",
+		IncludeAttributes: false,
+		AttributesToDisplay: &model.AttributesToDisplayScheme{
+			AttributesToDisplayIds: []int{135, 144},
+		},
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		payload     *model.ObjectSearchParamsScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/navlist/aql",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectListScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/object/navlist/aql",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectService := NewObjectService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectService.Search(testCase.args.ctx, testCase.args.workspaceID, testCase.args.payload)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
diff --git a/assets/internal/object_schema_impl_test.go b/assets/internal/object_schema_impl_test.go
new file mode 100644
index 0000000..d4339ed
--- /dev/null
+++ b/assets/internal/object_schema_impl_test.go
@@ -0,0 +1,918 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"net/http"
+	"testing"
+)
+
+func Test_internalObjectSchemaImpl_List(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/list",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectSchemaPageScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/list",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.List(testCase.args.ctx, testCase.args.workspaceID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_Get(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                         context.Context
+		workspaceID, objectSchemaID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectSchemaScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object schema id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectSchemaIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.Get(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectSchemaID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_Delete(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                         context.Context
+		workspaceID, objectSchemaID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectSchemaScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object schema id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectSchemaIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.Delete(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectSchemaID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_Attributes(t *testing.T) {
+
+	optionsMocked := &model.ObjectSchemaAttributesParamsScheme{
+		OnlyValueEditable: true,
+		Extended:          true,
+		Query:             "query sample",
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                         context.Context
+		workspaceID, objectSchemaID string
+		options                     *model.ObjectSchemaAttributesParamsScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+				options:        optionsMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample/attributes?extended=true&onlyValueEditable=true&onlyValueEditable=true&query=query+sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the options are not provided",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample/attributes",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+				options:        optionsMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample/attributes?extended=true&onlyValueEditable=true&onlyValueEditable=true&query=query+sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object schema id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectSchemaIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.Attributes(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectSchemaID,
+				testCase.args.options)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_ObjectTypes(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                         context.Context
+		workspaceID, objectSchemaID string
+		excludeAbstract             bool
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:             context.TODO(),
+				workspaceID:     "workspace-uuid-sample",
+				objectSchemaID:  "object-schema-id-sample",
+				excludeAbstract: true,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample/objecttypes?excludeAbstract=true",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:             context.TODO(),
+				workspaceID:     "workspace-uuid-sample",
+				objectSchemaID:  "object-schema-id-sample",
+				excludeAbstract: true,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample/objecttypes?excludeAbstract=true",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object schema id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectSchemaIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.ObjectTypes(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectSchemaID,
+				testCase.args.excludeAbstract)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_Update(t *testing.T) {
+
+	payloadMocked := &model.ObjectSchemaPayloadScheme{
+		Name:            "Computers",
+		ObjectSchemaKey: "COMP",
+		Description:     "The IT department schema",
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                         context.Context
+		workspaceID, objectSchemaID string
+		payload                     *model.ObjectSchemaPayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+				payload:        payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectSchemaScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:            context.TODO(),
+				workspaceID:    "workspace-uuid-sample",
+				objectSchemaID: "object-schema-id-sample",
+				payload:        payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/object-schema-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object schema id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectSchemaIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.Update(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectSchemaID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectSchemaImpl_Create(t *testing.T) {
+
+	payloadMocked := &model.ObjectSchemaPayloadScheme{
+		Name:            "Computers",
+		ObjectSchemaKey: "COMP",
+		Description:     "The IT department schema",
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		payload     *model.ObjectSchemaPayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectSchemaScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objectschema/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectSchemaService := NewObjectSchemaService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectSchemaService.Create(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
diff --git a/assets/internal/object_type_attribute_impl_test.go b/assets/internal/object_type_attribute_impl_test.go
new file mode 100644
index 0000000..07aaa71
--- /dev/null
+++ b/assets/internal/object_type_attribute_impl_test.go
@@ -0,0 +1,488 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"testing"
+)
+
+func Test_internalObjectTypeAttributeImpl_Create(t *testing.T) {
+
+	payloadMocked := &model.ObjectTypeAttributeScheme{
+		WorkspaceId: "g2778e1d-939d-581d-c8e2-9d5g59de456b",
+		GlobalId:    "g2778e1d-939d-581d-c8e2-9d5g59de456b:1330",
+		ID:          "1330",
+		ObjectType:  nil,
+		Name:        "Geolocation",
+		Label:       false,
+		Type:        0,
+		Description: "",
+		DefaultType: &model.ObjectTypeAssetAttributeDefaultTypeScheme{
+			ID:   0,
+			Name: "Text",
+		},
+		TypeValue:               "",
+		TypeValueMulti:          nil,
+		AdditionalValue:         "",
+		ReferenceType:           nil,
+		ReferenceObjectTypeId:   "",
+		ReferenceObjectType:     nil,
+		Editable:                false,
+		System:                  false,
+		Indexed:                 false,
+		Sortable:                false,
+		Summable:                false,
+		MinimumCardinality:      0,
+		MaximumCardinality:      0,
+		Suffix:                  "",
+		Removable:               false,
+		ObjectAttributeExists:   false,
+		Hidden:                  false,
+		IncludeChildObjectTypes: false,
+		UniqueAttribute:         false,
+		RegexValidation:         "",
+		Iql:                     "",
+		QlQuery:                 "",
+		Options:                 "",
+		Position:                6,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+		payload                   *model.ObjectTypeAttributeScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-uuid-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/object-type-uuid-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeAttributeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-uuid-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/object-type-uuid-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeAttributeService := NewObjectTypeAttributeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeAttributeService.Create(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectTypeID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeAttributeImpl_Update(t *testing.T) {
+
+	payloadMocked := &model.ObjectTypeAttributeScheme{
+		WorkspaceId: "g2778e1d-939d-581d-c8e2-9d5g59de456b",
+		GlobalId:    "g2778e1d-939d-581d-c8e2-9d5g59de456b:1330",
+		ID:          "1330",
+		ObjectType:  nil,
+		Name:        "Geolocation",
+		Label:       false,
+		Type:        0,
+		Description: "",
+		DefaultType: &model.ObjectTypeAssetAttributeDefaultTypeScheme{
+			ID:   0,
+			Name: "Text",
+		},
+		TypeValue:               "",
+		TypeValueMulti:          nil,
+		AdditionalValue:         "",
+		ReferenceType:           nil,
+		ReferenceObjectTypeId:   "",
+		ReferenceObjectType:     nil,
+		Editable:                false,
+		System:                  false,
+		Indexed:                 false,
+		Sortable:                false,
+		Summable:                false,
+		MinimumCardinality:      0,
+		MaximumCardinality:      0,
+		Suffix:                  "",
+		Removable:               false,
+		ObjectAttributeExists:   false,
+		Hidden:                  false,
+		IncludeChildObjectTypes: false,
+		UniqueAttribute:         false,
+		RegexValidation:         "",
+		Iql:                     "",
+		QlQuery:                 "",
+		Options:                 "",
+		Position:                6,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                                    context.Context
+		workspaceID, objectTypeID, attributeID string
+		payload                                *model.ObjectTypeAttributeScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-uuid-sample",
+				attributeID:  "attribute-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/object-type-uuid-sample/attribute-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeAttributeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-uuid-sample",
+				attributeID:  "attribute-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/object-type-uuid-sample/attribute-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+
+		{
+			name: "when the attribute id id is not provided",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeAttributeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeAttributeService := NewObjectTypeAttributeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeAttributeService.Update(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectTypeID,
+				testCase.args.attributeID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeAttributeImpl_Delete(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                      context.Context
+		workspaceID, attributeID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				attributeID: "attribute-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/attribute-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					nil).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				attributeID: "attribute-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttypeattribute/attribute-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the attribute id id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeAttributeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeAttributeService := NewObjectTypeAttributeService(testCase.fields.c)
+
+			gotResponse, err := newObjectTypeAttributeService.Delete(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.attributeID,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+			}
+		})
+	}
+}
diff --git a/assets/internal/object_type_impl_test.go b/assets/internal/object_type_impl_test.go
new file mode 100644
index 0000000..aa62723
--- /dev/null
+++ b/assets/internal/object_type_impl_test.go
@@ -0,0 +1,793 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"net/http"
+	"testing"
+)
+
+func Test_internalObjectTypeImpl_Get(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-id-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Get(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectTypeID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeImpl_Delete(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodDelete,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Delete(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectTypeID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeImpl_Attributes(t *testing.T) {
+
+	optionsMocked := &model.ObjectTypeAttributesParamsScheme{
+		OnlyValueEditable:       true,
+		OrderByName:             true,
+		Query:                   "aql-query-sample",
+		IncludeValuesExist:      true,
+		ExcludeParentAttributes: true,
+		IncludeChildren:         true,
+		OrderByRequired:         true,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+		options                   *model.ObjectTypeAttributesParamsScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				options:      optionsMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample/attributes?excludeParentAttributes=true&includeChildren=true&includeValuesExist=true&onlyValueEditable=true&orderByName=true&orderByRequired=true&query=aql-query-sample",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					mock.Anything).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				options:      optionsMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample/attributes?excludeParentAttributes=true&includeChildren=true&includeValuesExist=true&onlyValueEditable=true&orderByName=true&orderByRequired=true&query=aql-query-sample",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-id-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Attributes(testCase.args.ctx, testCase.args.workspaceID, testCase.args.objectTypeID,
+				testCase.args.options)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeImpl_Update(t *testing.T) {
+
+	payloadMocked := &model.ObjectTypePayloadScheme{
+		Name:               "Office",
+		Description:        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nec ex.",
+		IconId:             "13",
+		ObjectSchemaId:     "",
+		ParentObjectTypeId: "",
+		Inherited:          true,
+		AbstractObjectType: true,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+		payload                   *model.ObjectTypePayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPut,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Update(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectTypeID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeImpl_Create(t *testing.T) {
+
+	payloadMocked := &model.ObjectTypePayloadScheme{
+		Name:               "Office",
+		Description:        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nec ex.",
+		IconId:             "13",
+		ObjectSchemaId:     "",
+		ParentObjectTypeId: "",
+		Inherited:          true,
+		AbstractObjectType: true,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx         context.Context
+		workspaceID string
+		payload     *model.ObjectTypePayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+				payload:     payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/create",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Create(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+
+		})
+	}
+}
+
+func Test_internalObjectTypeImpl_Position(t *testing.T) {
+
+	payloadMocked := &model.ObjectTypePositionPayloadScheme{
+		ToObjectTypeId: "2",
+		Position:       0,
+	}
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx                       context.Context
+		workspaceID, objectTypeID string
+		payload                   *model.ObjectTypePositionPayloadScheme
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample/position",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.ObjectTypeScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http request cannot be created",
+			args: args{
+				ctx:          context.TODO(),
+				workspaceID:  "workspace-uuid-sample",
+				objectTypeID: "object-type-id-sample",
+				payload:      payloadMocked,
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodPost,
+					"jsm/assets/workspace/workspace-uuid-sample/v1/objecttype/object-type-id-sample/position",
+					"",
+					payloadMocked).
+					Return(&http.Request{}, errors.New("error, unable to create the http request"))
+
+				fields.c = client
+
+			},
+			wantErr: true,
+			Err:     errors.New("error, unable to create the http request"),
+		},
+
+		{
+			name: "when the workspace id is not provided",
+			args: args{
+				ctx: context.TODO(),
+			},
+			wantErr: true,
+			Err:     model.ErrNoWorkspaceIDError,
+		},
+
+		{
+			name: "when the object type id is not provided",
+			args: args{
+				ctx:         context.TODO(),
+				workspaceID: "workspace-uuid-sample",
+			},
+			wantErr: true,
+			Err:     model.ErrNoObjectTypeIDError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			newObjectTypeService := NewObjectTypeService(testCase.fields.c)
+
+			gotResult, gotResponse, err := newObjectTypeService.Position(
+				testCase.args.ctx,
+				testCase.args.workspaceID,
+				testCase.args.objectTypeID,
+				testCase.args.payload,
+			)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+		})
+	}
+}
diff --git a/jira/sm/internal/workspace_impl_test.go b/jira/sm/internal/workspace_impl_test.go
new file mode 100644
index 0000000..45b95a2
--- /dev/null
+++ b/jira/sm/internal/workspace_impl_test.go
@@ -0,0 +1,137 @@
+package internal
+
+import (
+	"context"
+	"errors"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/ctreminiom/go-atlassian/service"
+	"github.com/ctreminiom/go-atlassian/service/mocks"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"testing"
+)
+
+func Test_internalWorkSpaceImpl_Gets(t *testing.T) {
+
+	type fields struct {
+		c service.Connector
+	}
+
+	type args struct {
+		ctx context.Context
+	}
+
+	testCases := []struct {
+		name    string
+		fields  fields
+		args    args
+		on      func(*fields)
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				ctx: context.Background(),
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"/rest/servicedeskapi/assets/workspace",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.WorkSpacePageScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the http call cannot be executed",
+			args: args{
+				ctx: context.Background(),
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"/rest/servicedeskapi/assets/workspace",
+					"",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.WorkSpacePageScheme{}).
+					Return(&model.ResponseScheme{}, errors.New("client: no http response found"))
+
+				fields.c = client
+			},
+			Err:     errors.New("client: no http response found"),
+			wantErr: true,
+		},
+
+		{
+			name: "when the request cannot be created",
+			args: args{
+				ctx: context.Background(),
+			},
+			on: func(fields *fields) {
+
+				client := mocks.NewConnector(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"/rest/servicedeskapi/assets/workspace",
+					"",
+					nil).
+					Return(&http.Request{}, errors.New("client: no http request created"))
+
+				fields.c = client
+			},
+			Err:     errors.New("client: no http request created"),
+			wantErr: true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			if testCase.on != nil {
+				testCase.on(&testCase.fields)
+			}
+
+			workspaceService := NewWorkSpaceService(testCase.fields.c, "latest")
+
+			gotResult, gotResponse, err := workspaceService.Gets(testCase.args.ctx)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.Err.Error())
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+			}
+		})
+	}
+}
diff --git a/pkg/infra/models/jira_issue_custom_fields_test.go b/pkg/infra/models/jira_issue_custom_fields_test.go
index 4c17646..e1cb36f 100644
--- a/pkg/infra/models/jira_issue_custom_fields_test.go
+++ b/pkg/infra/models/jira_issue_custom_fields_test.go
@@ -1865,3 +1865,146 @@ func TestParseSelectCustomField(t *testing.T) {
 		})
 	}
 }
+
+func TestParseAssetCustomField(t *testing.T) {
+
+	bufferMocked := bytes.Buffer{}
+	bufferMocked.WriteString(`
+{
+	"fields": {
+		"customfield_10046": [
+      {
+        "workspaceId": "5e037d73-1c0a-43ce-adca-f169a42557f1",
+        "id": "5e037d73-1c0a-43ce-adca-f169a42557f1:1",
+        "objectId": "1"
+      }
+    ]
+	}
+}`)
+
+	bufferMockedWithNoFields := bytes.Buffer{}
+	bufferMockedWithNoFields.WriteString(`
+{
+	"field_no_mapped": {
+		"customfield_10046": [
+     {
+        "workspaceId": "5e037d73-1c0a-43ce-adca-f169a42557f1",
+        "id": "5e037d73-1c0a-43ce-adca-f169a42557f1:1",
+        "objectId": "1"
+      }
+    ]
+	}
+}`)
+
+	bufferMockedWithNoJSON := bytes.Buffer{}
+	bufferMockedWithNoJSON.WriteString(`{}{`)
+
+	bufferMockedWithNoInfo := bytes.Buffer{}
+	bufferMockedWithNoInfo.WriteString(`
+{
+	"fields": {
+		"customfield_10046": null
+	}
+}`)
+
+	bufferMockedWithInvalidType := bytes.Buffer{}
+	bufferMockedWithInvalidType.WriteString(`
+{
+	"fields": {
+		"customfield_10046": "Test field sample"
+	}
+}`)
+
+	type args struct {
+		buffer      bytes.Buffer
+		customField string
+	}
+
+	testCases := []struct {
+		name    string
+		args    args
+		want    []*CustomFieldAssetScheme
+		want1   bool
+		wantErr bool
+		Err     error
+	}{
+		{
+			name: "when the buffer contains information",
+			args: args{
+				buffer:      bufferMocked,
+				customField: "customfield_10046",
+			},
+			want: []*CustomFieldAssetScheme{
+				{
+					WorkspaceId: "5e037d73-1c0a-43ce-adca-f169a42557f1",
+					Id:          "5e037d73-1c0a-43ce-adca-f169a42557f1:1",
+					ObjectId:    "1",
+				},
+			},
+			want1:   true,
+			wantErr: false,
+		},
+
+		{
+			name: "when the buffer no contains information",
+			args: args{
+				buffer:      bufferMockedWithNoInfo,
+				customField: "customfield_10046",
+			},
+			want:    nil,
+			want1:   false,
+			wantErr: false,
+		},
+
+		{
+			name: "when the buffer does not contains the fields object",
+			args: args{
+				buffer:      bufferMockedWithNoFields,
+				customField: "customfield_10046",
+			},
+			want:    nil,
+			want1:   false,
+			wantErr: true,
+			Err:     ErrNoFieldInformationError,
+		},
+
+		{
+			name: "when the buffer does not contains a valid field type",
+			args: args{
+				buffer:      bufferMockedWithInvalidType,
+				customField: "customfield_10046",
+			},
+			want:    nil,
+			want1:   false,
+			wantErr: true,
+			Err:     ErrNoAssetTypeError,
+		},
+
+		{
+			name: "when the buffer cannot be parsed",
+			args: args{
+				buffer:      bufferMockedWithNoJSON,
+				customField: "customfield_10046",
+			},
+			want:    nil,
+			want1:   false,
+			wantErr: true,
+			Err:     ErrNoCustomFieldUnmarshalError,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got, err := ParseAssetCustomField(testCase.args.buffer, testCase.args.customField)
+			if (err != nil) != testCase.wantErr {
+				t.Errorf("ParseMultiSelectCustomField() error = %v, wantErr %v", err, testCase.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, testCase.want) {
+				t.Errorf("ParseMultiSelectCustomField() got = %v, want %v", got, testCase.want)
+			}
+			if !reflect.DeepEqual(err, testCase.Err) {
+				t.Errorf("ParseMultiSelectCustomField() got = (%v), want (%v)", err, testCase.Err)
+			}
+		})
+	}
+}