diff --git a/ocm/README.md b/ocm/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..68b44457a28e90fd875138c79e0f8b646f4e5682
--- /dev/null
+++ b/ocm/README.md
@@ -0,0 +1,20 @@
+#Golang Client package for the OCM Service
+
+This go package contains client for communication with the OCM service.
+
+###Usage
+
+In order to use this package you must import it in your application and
+instantiate the client given the OCM service address like this:
+
+```
+import "gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/ocm"
+
+func main() {
+    client := ocm.New(ocmAddress)
+}
+```
+
+###License
+
+See [LICENSE](../LICENSE) for the full license.
\ No newline at end of file
diff --git a/ocm/client.go b/ocm/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..9fded9bf695d427f993a5045eb8d3dd476c2d849
--- /dev/null
+++ b/ocm/client.go
@@ -0,0 +1,67 @@
+package ocm
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+)
+
+// Client is the OCM service client
+type Client struct {
+	addr       string
+	httpClient *http.Client
+}
+
+// New initializes an OCM service client given the OCM service address
+func New(addr string, opts ...Option) *Client {
+	c := &Client{
+		addr:       addr,
+		httpClient: http.DefaultClient,
+	}
+
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return c
+}
+
+// GetLoginProofInvitation calls the "invitation" endpoint on
+// the "out-of-band" protocol in the OCM service
+func (c *Client) GetLoginProofInvitation(ctx context.Context, r *LoginProofInvitationRequest) (*LoginProofInvitationResponse, error) {
+	b, err := json.Marshal(r)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http.NewRequestWithContext(ctx, "POST", c.addr+"/out-of-band/1.0/invitation", bytes.NewReader(b))
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := c.httpClient.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close() // nolint:errcheck
+
+	if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("unexpected response code: %d", resp.StatusCode)
+	}
+
+	bytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	response := &LoginProofInvitationResponse{}
+	err = json.Unmarshal(bytes, response)
+	if err != nil {
+		return nil, err
+	}
+
+	return response, nil
+}
diff --git a/ocm/option.go b/ocm/option.go
new file mode 100644
index 0000000000000000000000000000000000000000..3b7ba4cfbd986bdb96272ae92911e3f08b69781b
--- /dev/null
+++ b/ocm/option.go
@@ -0,0 +1,11 @@
+package ocm
+
+import "net/http"
+
+type Option func(*Client)
+
+func WithHTTPClient(client *http.Client) Option {
+	return func(c *Client) {
+		c.httpClient = client
+	}
+}
diff --git a/ocm/types.go b/ocm/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..3c1ad449e9957945a3fba50d5efc186a97dbe779
--- /dev/null
+++ b/ocm/types.go
@@ -0,0 +1,25 @@
+package ocm
+
+type LoginProofInvitationRequest struct {
+	Comment       string      `json:"comment"`
+	Attributes    []Attribute `json:"attributes"`
+	SchemaID      string      `json:"schemaId"`
+	ParticipantID string      `json:"participant_id"`
+}
+
+type Attribute struct {
+	AttributeName string `json:"attribute_name"`
+	Value         string `json:"value"`
+	Condition     string `json:"condition"`
+}
+
+type LoginProofInvitationResponse struct {
+	StatusCode int                              `json:"statusCode"`
+	Message    string                           `json:"message"`
+	Data       LoginProofInvitationResponseData `json:"data"`
+}
+
+type LoginProofInvitationResponseData struct {
+	PresentationID      string `json:"presentation_id"`
+	PresentationMessage string `json:"presentationMessage"`
+}