diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ca45ccd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Tilebox, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 80c4b67..88b6840 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,115 @@
## Introduction
-A Go SDK for interacting with [Loops's] API - generated from their [OpenAPI Spec](https://app.loops.so/openapi.json) using [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen).
+A Go SDK for interacting with [Loops's](https://loops.so) API.
+
+## Usage
+
+Below are a few examples of how to use the SDK to send API requests.
+For some full, working examples, see the [examples](examples) directory.
+
+**Create a client**:
+
+```go
+package main
+
+import (
+ "context"
+ "github.com/tilebox/loops-go"
+ "log/slog"
+)
+
+func main() {
+ ctx := context.Background()
+ client, err := loops.NewClient(loops.WithApiKey("YOUR_LOOPS_API_KEY"))
+ if err != nil {
+ slog.Error("failed to create client", slog.Any("error", err.Error()))
+ return
+ }
+
+ // now use the client to make requests
+}
+```
+
+### Contacts
+
+**Find a contact**
+```go
+contactToFind := &loops.ContactIdentifier{
+ Email: loops.String("neil.armstrong@moon.space"),
+}
+
+contact, err := client.FindContact(ctx, contactToFind)
+if err != nil {
+ slog.Error("failed to find contact", slog.Any("error", err.Error()))
+ return
+}
+```
+
+**Create a contact**
+```go
+newContact := &loops.Contact{
+ Email: "neil.armstrong@moon.space",
+ FirstName: loops.String("Neil"),
+ LastName: loops.String("Armstrong"),
+ UserGroup: loops.String("Astronauts"),
+ Subscribed: true,
+}
+
+contactID, err := client.CreateContact(ctx, newContact)
+if err != nil {
+ slog.Error("failed to create contact", slog.Any("error", err.Error()))
+ return
+}
+```
+
+**Delete a contact**
+```go
+contactToDelete := &loops.ContactIdentifier{
+ Email: loops.String("neil.armstrong@moon.space"),
+}
+
+err = client.DeleteContact(ctx, contactToDelete)
+if err != nil {
+ slog.Error("failed to delete contact", slog.Any("error", err.Error()))
+ return
+}
+```
+
+### Events
+
+**Send an event**
+```go
+err = client.SendEvent(ctx, &loops.Event{
+ Email: loops.String("neil.armstrong@moon.space"),
+ EventName: "joinedMission",
+ EventProperties: &map[string]interface{}{
+ "mission": "Apollo 11",
+ },
+})
+if err != nil {
+ slog.Error("failed to send event", slog.Any("error", err.Error()))
+ return
+}
+```
+
+### Transactional emails
+
+**Send a transactional email**
+
+```go
+err = client.SendTransactionalEmail(ctx, &loops.TransactionalEmail{
+ TransactionalId: "cm...",
+ Email: "recipient@example.com",
+ DataVariables: &map[string]interface{}{
+ "name": "Recipient Name",
+ },
+})
+if err != nil {
+ slog.Error("failed to send transactional email", slog.Any("error", err.Error()))
+ return
+}
+```
## Installation
diff --git a/client.go b/client.go
index 90156cc..44e63de 100644
--- a/client.go
+++ b/client.go
@@ -1,1558 +1,330 @@
-// Package loops provides primitives to interact with the openapi HTTP API.
-//
-// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
package loops
import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"net/http"
"net/url"
- "strings"
-
- "github.com/oapi-codegen/runtime"
-)
-
-const (
- ApiKeyScopes = "apiKey.Scopes"
)
-// Contact defines model for Contact.
-type Contact struct {
- Email *string `json:"email,omitempty"`
- FirstName *string `json:"firstName,omitempty"`
- Id *string `json:"id,omitempty"`
- LastName *string `json:"lastName,omitempty"`
-
- // MailingLists An object of mailing list IDs and boolean subscription statuses.
- MailingLists *map[string]interface{} `json:"mailingLists,omitempty"`
- Source *string `json:"source,omitempty"`
- Subscribed *bool `json:"subscribed,omitempty"`
- UserGroup *string `json:"userGroup,omitempty"`
- UserId *string `json:"userId,omitempty"`
-}
-
-// ContactDeleteRequest defines model for ContactDeleteRequest.
-type ContactDeleteRequest struct {
- Email string `json:"email"`
- UserId string `json:"userId"`
-}
-
-// ContactDeleteResponse defines model for ContactDeleteResponse.
-type ContactDeleteResponse struct {
- Message string `json:"message"`
- Success bool `json:"success"`
-}
-
-// ContactFailureResponse defines model for ContactFailureResponse.
-type ContactFailureResponse struct {
- Message string `json:"message"`
- Success bool `json:"success"`
-}
-
-// ContactRequest defines model for ContactRequest.
-type ContactRequest struct {
- Email string `json:"email"`
- FirstName *string `json:"firstName,omitempty"`
- LastName *string `json:"lastName,omitempty"`
-
- // MailingLists An object of mailing list IDs and boolean subscription statuses.
- MailingLists *map[string]interface{} `json:"mailingLists,omitempty"`
- Subscribed *bool `json:"subscribed,omitempty"`
- UserGroup *string `json:"userGroup,omitempty"`
- UserId *string `json:"userId,omitempty"`
-}
-
-// ContactSuccessResponse defines model for ContactSuccessResponse.
-type ContactSuccessResponse struct {
- Id string `json:"id"`
- Success bool `json:"success"`
-}
-
-// CustomField defines model for CustomField.
-type CustomField struct {
- Key string `json:"key"`
- Label string `json:"label"`
- Type string `json:"type"`
-}
-
-// EventFailureResponse defines model for EventFailureResponse.
-type EventFailureResponse struct {
- Message string `json:"message"`
- Success bool `json:"success"`
-}
-
-// EventRequest defines model for EventRequest.
-type EventRequest struct {
- Email *string `json:"email,omitempty"`
- EventName string `json:"eventName"`
-
- // EventProperties An object containing event property data for the event, available in emails sent by the event.
- EventProperties *map[string]interface{} `json:"eventProperties,omitempty"`
-
- // MailingLists An object of mailing list IDs and boolean subscription statuses.
- MailingLists *map[string]interface{} `json:"mailingLists,omitempty"`
- UserId *string `json:"userId,omitempty"`
-}
-
-// EventSuccessResponse defines model for EventSuccessResponse.
-type EventSuccessResponse struct {
- Success bool `json:"success"`
-}
-
-// MailingList defines model for MailingList.
-type MailingList struct {
- Id string `json:"id"`
- IsPublic bool `json:"isPublic"`
- Name string `json:"name"`
-}
-
-// TransactionalFailure2Response defines model for TransactionalFailure2Response.
-type TransactionalFailure2Response struct {
- Error struct {
- Message *string `json:"message,omitempty"`
- Path *string `json:"path,omitempty"`
- } `json:"error"`
- Success bool `json:"success"`
-}
-
-// TransactionalFailure3Response defines model for TransactionalFailure3Response.
-type TransactionalFailure3Response struct {
- Message string `json:"message"`
- Success bool `json:"success"`
-}
-
-// TransactionalFailureResponse defines model for TransactionalFailureResponse.
-type TransactionalFailureResponse struct {
- Message string `json:"message"`
- Path string `json:"path"`
- Success bool `json:"success"`
-}
-
-// TransactionalRequest defines model for TransactionalRequest.
-type TransactionalRequest struct {
- // AddToAudience If `true`, a contact will be created in your audience using the `email` value (if a matching contact doesn't already exist).
- AddToAudience *bool `json:"addToAudience,omitempty"`
-
- // Attachments A list containing file objects to be sent along with an email message.
- Attachments *[]struct {
- // ContentType The MIME type of the file.
- ContentType string `json:"contentType"`
-
- // Data The base64-encoded content of the file.
- Data string `json:"data"`
-
- // Filename The name of the file, shown in email clients.
- Filename string `json:"filename"`
- } `json:"attachments,omitempty"`
-
- // DataVariables An object containing contact data as defined by the data variables added to the transactional email template.
- DataVariables *map[string]interface{} `json:"dataVariables,omitempty"`
- Email string `json:"email"`
-
- // TransactionalId The ID of the transactional email to send.
- TransactionalId string `json:"transactionalId"`
-}
-
-// TransactionalSuccessResponse defines model for TransactionalSuccessResponse.
-type TransactionalSuccessResponse struct {
- Success bool `json:"success"`
-}
-
-// GetContactsFindParams defines parameters for GetContactsFind.
-type GetContactsFindParams struct {
- // Email Email address (URI-encoded)
- Email *string `form:"email,omitempty" json:"email,omitempty"`
- UserId *string `form:"userId,omitempty" json:"userId,omitempty"`
-}
-
-// PostContactsCreateJSONRequestBody defines body for PostContactsCreate for application/json ContentType.
-type PostContactsCreateJSONRequestBody = ContactRequest
-
-// PostContactsDeleteJSONRequestBody defines body for PostContactsDelete for application/json ContentType.
-type PostContactsDeleteJSONRequestBody = ContactDeleteRequest
-
-// PutContactsUpdateJSONRequestBody defines body for PutContactsUpdate for application/json ContentType.
-type PutContactsUpdateJSONRequestBody = ContactRequest
+const defaultApiURL = "https://app.loops.so/api/v1/"
-// PostEventsSendJSONRequestBody defines body for PostEventsSend for application/json ContentType.
-type PostEventsSendJSONRequestBody = EventRequest
+var ErrContactNotFound = errors.New("contact not found")
-// PostTransactionalJSONRequestBody defines body for PostTransactional for application/json ContentType.
-type PostTransactionalJSONRequestBody = TransactionalRequest
-
-// RequestEditorFn is the function signature for the RequestEditor callback function
-type RequestEditorFn func(ctx context.Context, req *http.Request) error
-
-// Doer performs HTTP requests.
-//
-// The standard http.Client implements this interface.
-type HttpRequestDoer interface {
+type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
-// Client which conforms to the OpenAPI3 specification for this service.
-type Client struct {
- // The endpoint of the server conforming to this interface, with scheme,
- // https://api.deepmap.com for example. This can contain a path relative
- // to the server, such as https://api.deepmap.com/dev-test, and all the
- // paths in the swagger spec will be appended to the server.
- Server string
-
- // Doer for performing requests, typically a *http.Client with any
- // customized settings, such as certificate chains.
- Client HttpRequestDoer
+type RequestInterceptor func(ctx context.Context, req *http.Request) error
- // A list of callbacks for modifying requests which are generated before sending over
- // the network.
- RequestEditors []RequestEditorFn
+type Client struct {
+ apiURL *url.URL
+ httpClient HttpClient
+ requestInterceptors []RequestInterceptor
}
-// ClientOption allows setting custom parameters during construction
-type ClientOption func(*Client) error
-
-// Creates a new Client, with reasonable defaults
-func NewClient(server string, opts ...ClientOption) (*Client, error) {
- // create a client with sane default values
- client := Client{
- Server: server,
+// NewClient creates a new Loops client.
+func NewClient(opts ...ClientOption) (*Client, error) {
+ config := clientConfig{
+ apiURL: defaultApiURL,
+ httpClient: http.DefaultClient,
}
- // mutate client and add all optional params
for _, o := range opts {
- if err := o(&client); err != nil {
- return nil, err
- }
- }
- // ensure the server URL always has a trailing slash
- if !strings.HasSuffix(client.Server, "/") {
- client.Server += "/"
+ o(&config)
}
- // create httpClient, if not already present
- if client.Client == nil {
- client.Client = &http.Client{}
+ apiURL, err := url.Parse(config.apiURL)
+ if err != nil {
+ return nil, fmt.Errorf("invalid api url: %w", err)
}
- return &client, nil
-}
-// WithHTTPClient allows overriding the default Doer, which is
-// automatically created using http.Client. This is useful for tests.
-func WithHTTPClient(doer HttpRequestDoer) ClientOption {
- return func(c *Client) error {
- c.Client = doer
- return nil
- }
-}
+ requestInterceptors := config.requestInterceptors
-// WithRequestEditorFn allows setting up a callback function, which will be
-// called right before sending the request. This can be used to mutate the request.
-func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
- return func(c *Client) error {
- c.RequestEditors = append(c.RequestEditors, fn)
- return nil
+ if config.apiKey != "" {
+ requestInterceptors = append(requestInterceptors, func(ctx context.Context, req *http.Request) error {
+ bearerToken := fmt.Sprintf("Bearer %s", config.apiKey)
+ req.Header.Set("Authorization", bearerToken)
+ return nil
+ })
}
-}
-
-// The interface specification for the client above.
-type ClientInterface interface {
- // GetApiKey request
- GetApiKey(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // PostContactsCreateWithBody request with any body
- PostContactsCreateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- PostContactsCreate(ctx context.Context, body PostContactsCreateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // GetContactsCustomFields request
- GetContactsCustomFields(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // PostContactsDeleteWithBody request with any body
- PostContactsDeleteWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- PostContactsDelete(ctx context.Context, body PostContactsDeleteJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // GetContactsFind request
- GetContactsFind(ctx context.Context, params *GetContactsFindParams, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PutContactsUpdateWithBody request with any body
- PutContactsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- PutContactsUpdate(ctx context.Context, body PutContactsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // PostEventsSendWithBody request with any body
- PostEventsSendWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- PostEventsSend(ctx context.Context, body PostEventsSendJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // GetLists request
- GetLists(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
-
- // PostTransactionalWithBody request with any body
- PostTransactionalWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ requestInterceptors = append(requestInterceptors, func(ctx context.Context, req *http.Request) error {
+ req.Header.Set("Content-Type", "application/json")
+ return nil
+ })
- PostTransactional(ctx context.Context, body PostTransactionalJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ return &Client{
+ apiURL: apiURL,
+ httpClient: config.httpClient,
+ requestInterceptors: requestInterceptors,
+ }, nil
}
-func (c *Client) GetApiKey(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetApiKeyRequest(c.Server)
- if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
+type clientConfig struct {
+ apiURL string
+ apiKey string
+ httpClient HttpClient
+ requestInterceptors []RequestInterceptor
}
-func (c *Client) PostContactsCreateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostContactsCreateRequestWithBody(c.Server, contentType, body)
- if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
-}
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*clientConfig)
-func (c *Client) PostContactsCreate(ctx context.Context, body PostContactsCreateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostContactsCreateRequest(c.Server, body)
- if err != nil {
- return nil, err
+// WithApiURL allows overriding the default API URL
+func WithApiURL(apiURL string) ClientOption {
+ return func(c *clientConfig) {
+ c.apiURL = apiURL
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
}
-func (c *Client) GetContactsCustomFields(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetContactsCustomFieldsRequest(c.Server)
- if err != nil {
- return nil, err
+// WithApiKey sets the loops API key to use
+func WithApiKey(apiKey string) ClientOption {
+ return func(c *clientConfig) {
+ c.apiKey = apiKey
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
}
-func (c *Client) PostContactsDeleteWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostContactsDeleteRequestWithBody(c.Server, contentType, body)
- if err != nil {
- return nil, err
+// WithHttpClient allows overriding the default http client, in case you want to use a custom one (e.g. retryablehttp)
+// or for testing purposes (e.g. mocking)
+func WithHttpClient(httpClient HttpClient) ClientOption {
+ return func(c *clientConfig) {
+ c.httpClient = httpClient
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
}
-func (c *Client) PostContactsDelete(ctx context.Context, body PostContactsDeleteJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostContactsDeleteRequest(c.Server, body)
- if err != nil {
- return nil, err
+// WithRequestInterceptors allows adding custom request interceptors, modifying API requests before they are sent
+func WithRequestInterceptors(requestInterceptors ...RequestInterceptor) ClientOption {
+ return func(c *clientConfig) {
+ c.requestInterceptors = append(c.requestInterceptors, requestInterceptors...)
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
}
-func (c *Client) GetContactsFind(ctx context.Context, params *GetContactsFindParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetContactsFindRequest(c.Server, params)
+// CreateContact creates a new contact with an email address and any other contact properties.
+// See: https://loops.so/docs/api-reference/create-contact
+func (c *Client) CreateContact(ctx context.Context, contact *Contact) (string, error) {
+ req, err := newRequestWithBody(c, ctx, http.MethodPost, "/contacts/create", contact)
if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ return "", err
}
- return c.Client.Do(req)
-}
-func (c *Client) PutContactsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPutContactsUpdateRequestWithBody(c.Server, contentType, body)
+ response, err := sendRequest[*IDResponse](c, req)
if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ return "", err
}
- return c.Client.Do(req)
+ return response.ID, err
}
-func (c *Client) PutContactsUpdate(ctx context.Context, body PutContactsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPutContactsUpdateRequest(c.Server, body)
+// UpdateContact updates or creates a contact.
+// See: https://loops.so/docs/api-reference/update-contact
+func (c *Client) UpdateContact(ctx context.Context, contact *Contact) (string, error) {
+ req, err := newRequestWithBody(c, ctx, http.MethodPut, "/contacts/update", contact)
if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ return "", err
}
- return c.Client.Do(req)
-}
-func (c *Client) PostEventsSendWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostEventsSendRequestWithBody(c.Server, contentType, body)
+ response, err := sendRequest[*IDResponse](c, req)
if err != nil {
- return nil, err
- }
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ return "", err
}
- return c.Client.Do(req)
+ return response.ID, err
}
-func (c *Client) PostEventsSend(ctx context.Context, body PostEventsSendJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostEventsSendRequest(c.Server, body)
- if err != nil {
- return nil, err
+// FindContact finds a contact by email or userId.
+// See: https://loops.so/docs/api-reference/find-contact
+func (c *Client) FindContact(ctx context.Context, contact *ContactIdentifier) (*Contact, error) {
+ if contact.Email == nil && contact.UserId == nil {
+ return nil, errors.New("contact identifier must contain either an email or a userId")
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ if contact.Email != nil && contact.UserId != nil {
+ return nil, errors.New("contact identifier must contain either an email or a userId, but not both")
}
- return c.Client.Do(req)
-}
-func (c *Client) GetLists(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetListsRequest(c.Server)
- if err != nil {
- return nil, err
+ params := url.Values{}
+ if contact.Email != nil {
+ params.Add("email", *contact.Email)
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ if contact.UserId != nil {
+ params.Add("userId", *contact.UserId)
}
- return c.Client.Do(req)
-}
-
-func (c *Client) PostTransactionalWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostTransactionalRequestWithBody(c.Server, contentType, body)
+ req, err := newRequestWithQueryParams(c, ctx, http.MethodGet, "/contacts/find", params)
if err != nil {
return nil, err
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
- }
- return c.Client.Do(req)
-}
-
-func (c *Client) PostTransactional(ctx context.Context, body PostTransactionalJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostTransactionalRequest(c.Server, body)
+ contacts, err := sendRequest[[]*Contact](c, req)
if err != nil {
return nil, err
}
- req = req.WithContext(ctx)
- if err := c.applyEditors(ctx, req, reqEditors); err != nil {
- return nil, err
+ if len(contacts) == 0 {
+ return nil, ErrContactNotFound
}
- return c.Client.Do(req)
+ return contacts[0], nil
}
-// NewGetApiKeyRequest generates requests for GetApiKey
-func NewGetApiKeyRequest(server string) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
- if err != nil {
- return nil, err
- }
-
- operationPath := fmt.Sprintf("/api-key")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
+// DeleteContact deletes a contact by email or userId.
+// See: https://loops.so/docs/api-reference/delete-contact
+func (c *Client) DeleteContact(ctx context.Context, contact *ContactIdentifier) error {
+ if contact.Email == nil && contact.UserId == nil {
+ return errors.New("contact identifier must contain either an email or a userId")
}
-
- req, err := http.NewRequest("GET", queryURL.String(), nil)
- if err != nil {
- return nil, err
+ if contact.Email != nil && contact.UserId != nil {
+ return errors.New("contact identifier must contain either an email or a userId, but not both")
}
- return req, nil
-}
-
-// NewPostContactsCreateRequest calls the generic PostContactsCreate builder with application/json body
-func NewPostContactsCreateRequest(server string, body PostContactsCreateJSONRequestBody) (*http.Request, error) {
- var bodyReader io.Reader
- buf, err := json.Marshal(body)
+ req, err := newRequestWithBody(c, ctx, http.MethodPost, "/contacts/delete", &contact)
if err != nil {
- return nil, err
+ return err
}
- bodyReader = bytes.NewReader(buf)
- return NewPostContactsCreateRequestWithBody(server, "application/json", bodyReader)
+ _, err = sendRequest[*MessageResponse](c, req)
+ return err
}
-// NewPostContactsCreateRequestWithBody generates requests for PostContactsCreate with any type of body
-func NewPostContactsCreateRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
- if err != nil {
- return nil, err
- }
-
- operationPath := fmt.Sprintf("/contacts/create")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
- }
-
- req, err := http.NewRequest("POST", queryURL.String(), body)
+// GetMailingLists retrieves a list of an account’s mailing lists.
+// See: https://loops.so/docs/api-reference/get-mailing-lists
+func (c *Client) GetMailingLists(ctx context.Context) ([]*MailingList, error) {
+ req, err := newRequestWithQueryParams(c, ctx, http.MethodGet, "/lists", nil)
if err != nil {
return nil, err
}
- req.Header.Add("Content-Type", contentType)
-
- return req, nil
+ return sendRequest[[]*MailingList](c, req)
}
-// NewGetContactsCustomFieldsRequest generates requests for GetContactsCustomFields
-func NewGetContactsCustomFieldsRequest(server string) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
- if err != nil {
- return nil, err
- }
-
- operationPath := fmt.Sprintf("/contacts/customFields")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
+// SendEvent sends an event to trigger emails in Loops.
+// See: https://loops.so/docs/api-reference/send-event
+func (c *Client) SendEvent(ctx context.Context, event *Event) error {
+ if event.Email == nil && event.UserId == nil {
+ return errors.New("event must contain either an email or a userId")
}
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
+ if event.Email != nil && event.UserId != nil {
+ return errors.New("event must contain either an email or a userId, but not both")
}
-
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := newRequestWithBody(c, ctx, http.MethodPost, "/events/send", event)
if err != nil {
- return nil, err
+ return err
}
-
- return req, nil
+ _, err = sendRequest[*MessageResponse](c, req)
+ return err
}
-// NewPostContactsDeleteRequest calls the generic PostContactsDelete builder with application/json body
-func NewPostContactsDeleteRequest(server string, body PostContactsDeleteJSONRequestBody) (*http.Request, error) {
- var bodyReader io.Reader
- buf, err := json.Marshal(body)
+// SendTransactionalEmail sends a transactional email to a contact.
+// See: https://loops.so/docs/api-reference/send-transactional-email
+func (c *Client) SendTransactionalEmail(ctx context.Context, transactional *TransactionalEmail) error {
+ req, err := newRequestWithBody(c, ctx, http.MethodPost, "/transactional", transactional)
if err != nil {
- return nil, err
+ return err
}
- bodyReader = bytes.NewReader(buf)
- return NewPostContactsDeleteRequestWithBody(server, "application/json", bodyReader)
+ _, err = sendRequest[*MessageResponse](c, req)
+ return err
}
-// NewPostContactsDeleteRequestWithBody generates requests for PostContactsDelete with any type of body
-func NewPostContactsDeleteRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
- if err != nil {
- return nil, err
- }
-
- operationPath := fmt.Sprintf("/contacts/delete")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
+// GetCustomFields retrieves a list of an account's custom contact properties.
+func (c *Client) GetCustomFields(ctx context.Context) ([]*CustomField, error) {
+ req, err := newRequestWithQueryParams(c, ctx, http.MethodGet, "/contacts/customFields", nil)
if err != nil {
return nil, err
}
-
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ customFields, err := sendRequest[[]*CustomField](c, req)
if err != nil {
return nil, err
}
-
- req.Header.Add("Content-Type", contentType)
-
- return req, nil
+ return customFields, nil
}
-// NewGetContactsFindRequest generates requests for GetContactsFind
-func NewGetContactsFindRequest(server string, params *GetContactsFindParams) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
- if err != nil {
- return nil, err
- }
-
- operationPath := fmt.Sprintf("/contacts/find")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
- }
-
- if params != nil {
- queryValues := queryURL.Query()
-
- if params.Email != nil {
-
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "email", runtime.ParamLocationQuery, *params.Email); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
- }
- }
-
- }
-
- if params.UserId != nil {
-
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "userId", runtime.ParamLocationQuery, *params.UserId); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
- }
- }
-
- }
-
- queryURL.RawQuery = queryValues.Encode()
- }
-
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+// TestApiKey tests that an API key is valid.
+// See: https://loops.so/docs/api-reference/api-key
+func (c *Client) TestApiKey(ctx context.Context) (*ApiKeyInfo, error) {
+ req, err := newRequestWithQueryParams(c, ctx, http.MethodGet, "/api-key", nil)
if err != nil {
return nil, err
}
- return req, nil
-}
-
-// NewPutContactsUpdateRequest calls the generic PutContactsUpdate builder with application/json body
-func NewPutContactsUpdateRequest(server string, body PutContactsUpdateJSONRequestBody) (*http.Request, error) {
- var bodyReader io.Reader
- buf, err := json.Marshal(body)
- if err != nil {
- return nil, err
- }
- bodyReader = bytes.NewReader(buf)
- return NewPutContactsUpdateRequestWithBody(server, "application/json", bodyReader)
+ return sendRequest[*ApiKeyInfo](c, req)
}
-// NewPutContactsUpdateRequestWithBody generates requests for PutContactsUpdate with any type of body
-func NewPutContactsUpdateRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
+func newRequestWithQueryParams(c *Client, ctx context.Context, method, path string, queryParams url.Values) (*http.Request, error) {
+ req, err := newRequestWithBody[Contact](c, ctx, method, path, nil)
if err != nil {
return nil, err
}
-
- operationPath := fmt.Sprintf("/contacts/update")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
- }
-
- req, err := http.NewRequest("PUT", queryURL.String(), body)
- if err != nil {
- return nil, err
+ if queryParams != nil {
+ req.URL.RawQuery = queryParams.Encode()
}
- req.Header.Add("Content-Type", contentType)
-
return req, nil
}
-// NewPostEventsSendRequest calls the generic PostEventsSend builder with application/json body
-func NewPostEventsSendRequest(server string, body PostEventsSendJSONRequestBody) (*http.Request, error) {
- var bodyReader io.Reader
- buf, err := json.Marshal(body)
- if err != nil {
- return nil, err
+func newRequestWithBody[T any](c *Client, ctx context.Context, method, path string, message *T) (*http.Request, error) {
+ if path[0] == '/' {
+ path = "." + path
}
- bodyReader = bytes.NewReader(buf)
- return NewPostEventsSendRequestWithBody(server, "application/json", bodyReader)
-}
-
-// NewPostEventsSendRequestWithBody generates requests for PostEventsSend with any type of body
-func NewPostEventsSendRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
- var err error
- serverURL, err := url.Parse(server)
+ queryURL, err := c.apiURL.Parse(path)
if err != nil {
return nil, err
}
- operationPath := fmt.Sprintf("/events/send")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
+ var body io.Reader
+ if message != nil {
+ buf, err := json.Marshal(message)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal message: %w", err)
+ }
+ body = bytes.NewReader(buf)
}
- queryURL, err := serverURL.Parse(operationPath)
+ req, err := http.NewRequestWithContext(ctx, method, queryURL.String(), body)
if err != nil {
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
- if err != nil {
- return nil, err
+ for _, interceptor := range c.requestInterceptors {
+ if err := interceptor(ctx, req); err != nil {
+ return nil, err
+ }
}
-
- req.Header.Add("Content-Type", contentType)
-
return req, nil
}
-// NewGetListsRequest generates requests for GetLists
-func NewGetListsRequest(server string) (*http.Request, error) {
- var err error
-
- serverURL, err := url.Parse(server)
+func sendRequest[T any](c *Client, req *http.Request) (T, error) {
+ var none T
+ resp, err := c.httpClient.Do(req)
if err != nil {
- return nil, err
+ return none, fmt.Errorf("failed to send request %s: %w", req.URL.String(), err)
}
+ defer func() { _ = resp.Body.Close() }()
- operationPath := fmt.Sprintf("/lists")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
- }
-
- queryURL, err := serverURL.Parse(operationPath)
+ body, err := io.ReadAll(resp.Body)
if err != nil {
- return nil, err
+ return none, fmt.Errorf("failed to read response body: %w", err)
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
- if err != nil {
- return nil, err
+ if resp.StatusCode < 300 { // success response
+ var response T
+ err = json.Unmarshal(body, &response)
+ if err != nil {
+ return none, fmt.Errorf("failed to unmarshal response body: %w", err)
+ }
+ return response, nil
}
- return req, nil
-}
-
-// NewPostTransactionalRequest calls the generic PostTransactional builder with application/json body
-func NewPostTransactionalRequest(server string, body PostTransactionalJSONRequestBody) (*http.Request, error) {
- var bodyReader io.Reader
- buf, err := json.Marshal(body)
- if err != nil {
- return nil, err
+ // sometimes loops returns an "error": message, so check if that's the case and if so, return the error
+ errorMsg := &errorResponse{}
+ err = json.Unmarshal(body, &errorMsg)
+ if err == nil {
+ return none, errors.New(errorMsg.Error)
}
- bodyReader = bytes.NewReader(buf)
- return NewPostTransactionalRequestWithBody(server, "application/json", bodyReader)
-}
-
-// NewPostTransactionalRequestWithBody generates requests for PostTransactional with any type of body
-func NewPostTransactionalRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
- var err error
- serverURL, err := url.Parse(server)
+ // error, get the message and return it
+ msg := &MessageResponse{}
+ err = json.Unmarshal(body, &msg)
if err != nil {
- return nil, err
+ return none, fmt.Errorf("failed to unmarshal error message: %w", err)
}
-
- operationPath := fmt.Sprintf("/transactional")
- if operationPath[0] == '/' {
- operationPath = "." + operationPath
+ if msg.Message == "" {
+ return none, errors.New(string(body))
}
-
- queryURL, err := serverURL.Parse(operationPath)
- if err != nil {
- return nil, err
- }
-
- req, err := http.NewRequest("POST", queryURL.String(), body)
- if err != nil {
- return nil, err
- }
-
- req.Header.Add("Content-Type", contentType)
-
- return req, nil
-}
-
-func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
- for _, r := range c.RequestEditors {
- if err := r(ctx, req); err != nil {
- return err
- }
- }
- for _, r := range additionalEditors {
- if err := r(ctx, req); err != nil {
- return err
- }
- }
- return nil
-}
-
-// ClientWithResponses builds on ClientInterface to offer response payloads
-type ClientWithResponses struct {
- ClientInterface
-}
-
-// NewClientWithResponses creates a new ClientWithResponses, which wraps
-// Client with return type handling
-func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
- client, err := NewClient(server, opts...)
- if err != nil {
- return nil, err
- }
- return &ClientWithResponses{client}, nil
-}
-
-// WithBaseURL overrides the baseURL.
-func WithBaseURL(baseURL string) ClientOption {
- return func(c *Client) error {
- newBaseURL, err := url.Parse(baseURL)
- if err != nil {
- return err
- }
- c.Server = newBaseURL.String()
- return nil
- }
-}
-
-// ClientWithResponsesInterface is the interface specification for the client with responses above.
-type ClientWithResponsesInterface interface {
- // GetApiKeyWithResponse request
- GetApiKeyWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiKeyResponse, error)
-
- // PostContactsCreateWithBodyWithResponse request with any body
- PostContactsCreateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostContactsCreateResponse, error)
-
- PostContactsCreateWithResponse(ctx context.Context, body PostContactsCreateJSONRequestBody, reqEditors ...RequestEditorFn) (*PostContactsCreateResponse, error)
-
- // GetContactsCustomFieldsWithResponse request
- GetContactsCustomFieldsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetContactsCustomFieldsResponse, error)
-
- // PostContactsDeleteWithBodyWithResponse request with any body
- PostContactsDeleteWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostContactsDeleteResponse, error)
-
- PostContactsDeleteWithResponse(ctx context.Context, body PostContactsDeleteJSONRequestBody, reqEditors ...RequestEditorFn) (*PostContactsDeleteResponse, error)
-
- // GetContactsFindWithResponse request
- GetContactsFindWithResponse(ctx context.Context, params *GetContactsFindParams, reqEditors ...RequestEditorFn) (*GetContactsFindResponse, error)
-
- // PutContactsUpdateWithBodyWithResponse request with any body
- PutContactsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutContactsUpdateResponse, error)
-
- PutContactsUpdateWithResponse(ctx context.Context, body PutContactsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*PutContactsUpdateResponse, error)
-
- // PostEventsSendWithBodyWithResponse request with any body
- PostEventsSendWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostEventsSendResponse, error)
-
- PostEventsSendWithResponse(ctx context.Context, body PostEventsSendJSONRequestBody, reqEditors ...RequestEditorFn) (*PostEventsSendResponse, error)
-
- // GetListsWithResponse request
- GetListsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetListsResponse, error)
-
- // PostTransactionalWithBodyWithResponse request with any body
- PostTransactionalWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostTransactionalResponse, error)
-
- PostTransactionalWithResponse(ctx context.Context, body PostTransactionalJSONRequestBody, reqEditors ...RequestEditorFn) (*PostTransactionalResponse, error)
-}
-
-type GetApiKeyResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *struct {
- Success bool `json:"success"`
-
- // TeamName The name of the team the API key belongs to.
- TeamName string `json:"teamName"`
- }
- JSON401 *struct {
- Error *string `json:"error,omitempty"`
- }
-}
-
-// Status returns HTTPResponse.Status
-func (r GetApiKeyResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r GetApiKeyResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type PostContactsCreateResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *ContactSuccessResponse
- JSON400 *ContactFailureResponse
- JSON405 *ContactFailureResponse
- JSON409 *ContactFailureResponse
-}
-
-// Status returns HTTPResponse.Status
-func (r PostContactsCreateResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r PostContactsCreateResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type GetContactsCustomFieldsResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *[]CustomField
-}
-
-// Status returns HTTPResponse.Status
-func (r GetContactsCustomFieldsResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r GetContactsCustomFieldsResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type PostContactsDeleteResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *ContactDeleteResponse
- JSON400 *ContactFailureResponse
- JSON404 *ContactFailureResponse
-}
-
-// Status returns HTTPResponse.Status
-func (r PostContactsDeleteResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r PostContactsDeleteResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type GetContactsFindResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *[]Contact
- JSON400 *ContactFailureResponse
-}
-
-// Status returns HTTPResponse.Status
-func (r GetContactsFindResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r GetContactsFindResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type PutContactsUpdateResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *ContactSuccessResponse
- JSON400 *ContactFailureResponse
- JSON405 *ContactFailureResponse
-}
-
-// Status returns HTTPResponse.Status
-func (r PutContactsUpdateResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r PutContactsUpdateResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type PostEventsSendResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *EventSuccessResponse
- JSON400 *EventFailureResponse
-}
-
-// Status returns HTTPResponse.Status
-func (r PostEventsSendResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r PostEventsSendResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type GetListsResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *[]MailingList
-}
-
-// Status returns HTTPResponse.Status
-func (r GetListsResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r GetListsResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-type PostTransactionalResponse struct {
- Body []byte
- HTTPResponse *http.Response
- JSON200 *TransactionalSuccessResponse
- JSON400 *struct {
- union json.RawMessage
- }
- JSON404 *TransactionalFailure2Response
-}
-
-// Status returns HTTPResponse.Status
-func (r PostTransactionalResponse) Status() string {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.Status
- }
- return http.StatusText(0)
-}
-
-// StatusCode returns HTTPResponse.StatusCode
-func (r PostTransactionalResponse) StatusCode() int {
- if r.HTTPResponse != nil {
- return r.HTTPResponse.StatusCode
- }
- return 0
-}
-
-// GetApiKeyWithResponse request returning *GetApiKeyResponse
-func (c *ClientWithResponses) GetApiKeyWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiKeyResponse, error) {
- rsp, err := c.GetApiKey(ctx, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParseGetApiKeyResponse(rsp)
-}
-
-// PostContactsCreateWithBodyWithResponse request with arbitrary body returning *PostContactsCreateResponse
-func (c *ClientWithResponses) PostContactsCreateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostContactsCreateResponse, error) {
- rsp, err := c.PostContactsCreateWithBody(ctx, contentType, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostContactsCreateResponse(rsp)
-}
-
-func (c *ClientWithResponses) PostContactsCreateWithResponse(ctx context.Context, body PostContactsCreateJSONRequestBody, reqEditors ...RequestEditorFn) (*PostContactsCreateResponse, error) {
- rsp, err := c.PostContactsCreate(ctx, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostContactsCreateResponse(rsp)
-}
-
-// GetContactsCustomFieldsWithResponse request returning *GetContactsCustomFieldsResponse
-func (c *ClientWithResponses) GetContactsCustomFieldsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetContactsCustomFieldsResponse, error) {
- rsp, err := c.GetContactsCustomFields(ctx, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParseGetContactsCustomFieldsResponse(rsp)
-}
-
-// PostContactsDeleteWithBodyWithResponse request with arbitrary body returning *PostContactsDeleteResponse
-func (c *ClientWithResponses) PostContactsDeleteWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostContactsDeleteResponse, error) {
- rsp, err := c.PostContactsDeleteWithBody(ctx, contentType, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostContactsDeleteResponse(rsp)
-}
-
-func (c *ClientWithResponses) PostContactsDeleteWithResponse(ctx context.Context, body PostContactsDeleteJSONRequestBody, reqEditors ...RequestEditorFn) (*PostContactsDeleteResponse, error) {
- rsp, err := c.PostContactsDelete(ctx, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostContactsDeleteResponse(rsp)
-}
-
-// GetContactsFindWithResponse request returning *GetContactsFindResponse
-func (c *ClientWithResponses) GetContactsFindWithResponse(ctx context.Context, params *GetContactsFindParams, reqEditors ...RequestEditorFn) (*GetContactsFindResponse, error) {
- rsp, err := c.GetContactsFind(ctx, params, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParseGetContactsFindResponse(rsp)
-}
-
-// PutContactsUpdateWithBodyWithResponse request with arbitrary body returning *PutContactsUpdateResponse
-func (c *ClientWithResponses) PutContactsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PutContactsUpdateResponse, error) {
- rsp, err := c.PutContactsUpdateWithBody(ctx, contentType, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePutContactsUpdateResponse(rsp)
-}
-
-func (c *ClientWithResponses) PutContactsUpdateWithResponse(ctx context.Context, body PutContactsUpdateJSONRequestBody, reqEditors ...RequestEditorFn) (*PutContactsUpdateResponse, error) {
- rsp, err := c.PutContactsUpdate(ctx, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePutContactsUpdateResponse(rsp)
-}
-
-// PostEventsSendWithBodyWithResponse request with arbitrary body returning *PostEventsSendResponse
-func (c *ClientWithResponses) PostEventsSendWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostEventsSendResponse, error) {
- rsp, err := c.PostEventsSendWithBody(ctx, contentType, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostEventsSendResponse(rsp)
-}
-
-func (c *ClientWithResponses) PostEventsSendWithResponse(ctx context.Context, body PostEventsSendJSONRequestBody, reqEditors ...RequestEditorFn) (*PostEventsSendResponse, error) {
- rsp, err := c.PostEventsSend(ctx, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostEventsSendResponse(rsp)
-}
-
-// GetListsWithResponse request returning *GetListsResponse
-func (c *ClientWithResponses) GetListsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetListsResponse, error) {
- rsp, err := c.GetLists(ctx, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParseGetListsResponse(rsp)
-}
-
-// PostTransactionalWithBodyWithResponse request with arbitrary body returning *PostTransactionalResponse
-func (c *ClientWithResponses) PostTransactionalWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostTransactionalResponse, error) {
- rsp, err := c.PostTransactionalWithBody(ctx, contentType, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostTransactionalResponse(rsp)
-}
-
-func (c *ClientWithResponses) PostTransactionalWithResponse(ctx context.Context, body PostTransactionalJSONRequestBody, reqEditors ...RequestEditorFn) (*PostTransactionalResponse, error) {
- rsp, err := c.PostTransactional(ctx, body, reqEditors...)
- if err != nil {
- return nil, err
- }
- return ParsePostTransactionalResponse(rsp)
-}
-
-// ParseGetApiKeyResponse parses an HTTP response from a GetApiKeyWithResponse call
-func ParseGetApiKeyResponse(rsp *http.Response) (*GetApiKeyResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &GetApiKeyResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest struct {
- Success bool `json:"success"`
-
- // TeamName The name of the team the API key belongs to.
- TeamName string `json:"teamName"`
- }
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401:
- var dest struct {
- Error *string `json:"error,omitempty"`
- }
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON401 = &dest
-
- }
-
- return response, nil
-}
-
-// ParsePostContactsCreateResponse parses an HTTP response from a PostContactsCreateWithResponse call
-func ParsePostContactsCreateResponse(rsp *http.Response) (*PostContactsCreateResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &PostContactsCreateResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest ContactSuccessResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 405:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON405 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON409 = &dest
-
- }
-
- return response, nil
-}
-
-// ParseGetContactsCustomFieldsResponse parses an HTTP response from a GetContactsCustomFieldsWithResponse call
-func ParseGetContactsCustomFieldsResponse(rsp *http.Response) (*GetContactsCustomFieldsResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &GetContactsCustomFieldsResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest []CustomField
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- }
-
- return response, nil
-}
-
-// ParsePostContactsDeleteResponse parses an HTTP response from a PostContactsDeleteWithResponse call
-func ParsePostContactsDeleteResponse(rsp *http.Response) (*PostContactsDeleteResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &PostContactsDeleteResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest ContactDeleteResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON404 = &dest
-
- }
-
- return response, nil
-}
-
-// ParseGetContactsFindResponse parses an HTTP response from a GetContactsFindWithResponse call
-func ParseGetContactsFindResponse(rsp *http.Response) (*GetContactsFindResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &GetContactsFindResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest []Contact
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- }
-
- return response, nil
-}
-
-// ParsePutContactsUpdateResponse parses an HTTP response from a PutContactsUpdateWithResponse call
-func ParsePutContactsUpdateResponse(rsp *http.Response) (*PutContactsUpdateResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &PutContactsUpdateResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest ContactSuccessResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 405:
- var dest ContactFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON405 = &dest
-
- }
-
- return response, nil
-}
-
-// ParsePostEventsSendResponse parses an HTTP response from a PostEventsSendWithResponse call
-func ParsePostEventsSendResponse(rsp *http.Response) (*PostEventsSendResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &PostEventsSendResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest EventSuccessResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest EventFailureResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- }
-
- return response, nil
-}
-
-// ParseGetListsResponse parses an HTTP response from a GetListsWithResponse call
-func ParseGetListsResponse(rsp *http.Response) (*GetListsResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &GetListsResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest []MailingList
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- }
-
- return response, nil
-}
-
-// ParsePostTransactionalResponse parses an HTTP response from a PostTransactionalWithResponse call
-func ParsePostTransactionalResponse(rsp *http.Response) (*PostTransactionalResponse, error) {
- bodyBytes, err := io.ReadAll(rsp.Body)
- defer func() { _ = rsp.Body.Close() }()
- if err != nil {
- return nil, err
- }
-
- response := &PostTransactionalResponse{
- Body: bodyBytes,
- HTTPResponse: rsp,
- }
-
- switch {
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest TransactionalSuccessResponse
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON200 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
- var dest struct {
- union json.RawMessage
- }
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON400 = &dest
-
- case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
- var dest TransactionalFailure2Response
- if err := json.Unmarshal(bodyBytes, &dest); err != nil {
- return nil, err
- }
- response.JSON404 = &dest
-
- }
-
- return response, nil
+ return none, errors.New(msg.Message)
}
diff --git a/examples/contact-crud/main.go b/examples/contact-crud/main.go
new file mode 100644
index 0000000..d64c637
--- /dev/null
+++ b/examples/contact-crud/main.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "context"
+ "github.com/tilebox/loops-go"
+ "log/slog"
+)
+
+func main() {
+ client, err := loops.NewClient(loops.WithApiKey("YOUR_LOOPS_API_KEY"))
+ if err != nil {
+ slog.Error("failed to create client", slog.Any("error", err.Error()))
+ return
+ }
+
+ ctx := context.Background()
+
+ // create a contact
+ contactID, err := client.CreateContact(ctx, &loops.Contact{
+ Email: "neil.armstrong@moon.space",
+ FirstName: loops.String("Neil"),
+ LastName: loops.String("Armstrong"),
+ Subscribed: true,
+ })
+ if err != nil {
+ slog.Error("failed to create contact", slog.Any("error", err.Error()))
+ return
+ }
+ slog.Info("Created contact", slog.String("id", contactID))
+
+ // find a contact
+ contact, err := client.FindContact(ctx, &loops.ContactIdentifier{
+ Email: loops.String("neil.armstrong@moon.space"),
+ })
+ if err != nil {
+ slog.Error("failed to find contact", slog.Any("error", err.Error()))
+ return
+ }
+ slog.Info("Found contact", slog.String("id", contact.Id), slog.String("email", contact.Email))
+
+ // update a contact, specify a user group
+ _, err = client.UpdateContact(ctx, &loops.Contact{
+ Email: "neil.armstrong@moon.space",
+ UserGroup: loops.String("Astronauts"),
+ })
+
+ // delete a contact
+ err = client.DeleteContact(ctx, &loops.ContactIdentifier{
+ Email: loops.String("neil.armstrong@moon.space"),
+ })
+ if err != nil {
+ slog.Error("failed to delete contact", slog.Any("error", err.Error()))
+ return
+ }
+}
diff --git a/examples/send-event/main.go b/examples/send-event/main.go
new file mode 100644
index 0000000..1158980
--- /dev/null
+++ b/examples/send-event/main.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "context"
+ "github.com/tilebox/loops-go"
+ "log/slog"
+)
+
+func main() {
+ client, err := loops.NewClient(loops.WithApiKey("YOUR_LOOPS_API_KEY"))
+ if err != nil {
+ slog.Error("failed to create client", slog.Any("error", err.Error()))
+ return
+ }
+
+ ctx := context.Background()
+
+ err = client.SendEvent(ctx, &loops.Event{
+ Email: loops.String("neil.armstrong@moon.space"),
+ EventName: "joinedMission",
+ EventProperties: &map[string]interface{}{
+ "mission": "Apollo 11",
+ },
+ })
+ if err != nil {
+ slog.Error("failed to send event", slog.Any("error", err.Error()))
+ return
+ }
+ slog.Info("sent event")
+}
diff --git a/examples/send-transactional-email/main.go b/examples/send-transactional-email/main.go
new file mode 100644
index 0000000..16c0eb2
--- /dev/null
+++ b/examples/send-transactional-email/main.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "context"
+ "github.com/tilebox/loops-go"
+ "log/slog"
+)
+
+func main() {
+ client, err := loops.NewClient(loops.WithApiKey("YOUR_LOOPS_API_KEY"))
+ if err != nil {
+ slog.Error("failed to create client", slog.Any("error", err.Error()))
+ return
+ }
+
+ ctx := context.Background()
+
+ err = client.SendTransactionalEmail(ctx, &loops.TransactionalEmail{
+ TransactionalId: "cm3n2vjux00cgeyeflew9ly2w",
+ Email: "lukas.bindreiter@tilebox.com",
+ DataVariables: &map[string]interface{}{
+ "name": "Mr. Lukas",
+ },
+ })
+ if err != nil {
+ slog.Error("failed to send transactional email", slog.Any("error", err.Error()))
+ return
+ }
+ slog.Info("sent transactional email")
+}
diff --git a/generate.go b/generate.go
deleted file mode 100644
index 1503d44..0000000
--- a/generate.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package loops
-
-//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=oapi_codegen_config.yaml openapi.json
diff --git a/go.mod b/go.mod
index b42713c..082215a 100644
--- a/go.mod
+++ b/go.mod
@@ -5,17 +5,14 @@ go 1.23.3
require github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
require (
- github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/getkin/kin-openapi v0.127.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
- github.com/google/uuid v1.5.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/oapi-codegen/runtime v1.1.1 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
diff --git a/go.sum b/go.sum
index 998e2ba..fc9e9df 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,3 @@
-github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
-github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
-github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -39,15 +35,12 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
-github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -64,8 +57,6 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q=
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8=
-github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
-github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
@@ -89,9 +80,7 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg=
github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc=
-github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
diff --git a/models.go b/models.go
new file mode 100644
index 0000000..76c9a8d
--- /dev/null
+++ b/models.go
@@ -0,0 +1,109 @@
+package loops
+
+// String returns a pointer to the string value passed in.
+func String(v string) *string {
+ return &v
+}
+
+// Contact defines model for Contact.
+type Contact struct {
+ // The contact's ID.
+ Id string `json:"id,omitempty"`
+ // The contact's email address.
+ Email string `json:"email,omitempty"`
+ // The contact's first name.
+ FirstName *string `json:"firstName,omitempty"`
+ // The contact's last name.
+ LastName *string `json:"lastName,omitempty"`
+ // The source the contact was created from.
+ Source *string `json:"source,omitempty"`
+ // Whether the contact will receive campaign and loops emails.
+ Subscribed bool `json:"subscribed,omitempty"`
+ // The contact's user group (used to segemnt users when sending emails).
+ UserGroup *string `json:"userGroup,omitempty"`
+ // A unique user ID (for example, from an external application).
+ UserId *string `json:"userId,omitempty"`
+ // Mailing lists the contact is subscribed to.
+ MailingLists map[string]interface{} `json:"mailingLists,omitempty"`
+}
+
+type ContactIdentifier struct {
+ Email *string `json:"email,omitempty"`
+ UserId *string `json:"userId,omitempty"`
+}
+
+type MailingList struct {
+ // The ID of the list.
+ Id string `json:"id"`
+ // The name of the list.
+ Name string `json:"name"`
+ // Whether the list is public (true) or private (false).
+ // See: https://loops.so/docs/contacts/mailing-lists#list-visibility
+ IsPublic bool `json:"isPublic"`
+}
+
+type Event struct {
+ // The contact's email address
+ Email *string `json:"email,omitempty"`
+ // The contact's unique user ID. This must already have been added to your contact in Loops.
+ UserId *string `json:"userId,omitempty"`
+ // The name of the event
+ EventName string `json:"eventName"`
+ // Properties to update the contact with, including custom properties.
+ ContactProperties map[string]interface{} `json:"contactProperties,omitempty"`
+ // Event properties, made available in emails triggered by the event.
+ EventProperties *map[string]interface{} `json:"eventProperties,omitempty"`
+ // An object of mailing list IDs and boolean subscription statuses.
+ MailingLists *map[string]interface{} `json:"mailingLists,omitempty"`
+}
+
+type TransactionalEmail struct {
+ // The ID of the transactional email to send.
+ TransactionalId string `json:"transactionalId"`
+ // The email address of the recipient
+ Email string `json:"email"`
+ // Create a contact in your audience using the provided email address (if one doesn't already exist).
+ AddToAudience *bool `json:"addToAudience,omitempty"`
+ // Data variables as defined by the transational email template.
+ DataVariables *map[string]interface{} `json:"dataVariables,omitempty"`
+ // File(s) to be sent along with the email message.
+ Attachments *[]EmailAttachment `json:"attachments,omitempty"`
+}
+
+type EmailAttachment struct {
+ // Filename The name of the file, shown in email clients.
+ Filename string `json:"filename"`
+ // ContentType The MIME type of the file.
+ ContentType string `json:"contentType"`
+ // Data The base64-encoded content of the file.
+ Data string `json:"data"`
+}
+
+type CustomField struct {
+ // The property's name key
+ Key string `json:"key"`
+ // The human-friendly label for this property
+ Label string `json:"label"`
+ // The type of property (one of string, number, boolean or date)
+ Type string `json:"type"`
+}
+
+type ApiKeyInfo struct {
+ Success bool `json:"success"`
+ // The name of the team the API key belongs to.
+ TeamName string `json:"teamName"`
+}
+
+type errorResponse struct {
+ Error string `json:"error"`
+}
+
+type IDResponse struct {
+ Success bool `json:"success"`
+ ID string `json:"id"`
+}
+
+type MessageResponse struct {
+ Success bool `json:"success"`
+ Message string `json:"message"`
+}
diff --git a/oapi_codegen_config.yaml b/oapi_codegen_config.yaml
deleted file mode 100644
index ed0c653..0000000
--- a/oapi_codegen_config.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
-package: loops
-output: client.go
-generate:
- client: true
- models: true
diff --git a/openapi.json b/openapi.json
deleted file mode 100644
index 48fa270..0000000
--- a/openapi.json
+++ /dev/null
@@ -1,935 +0,0 @@
-{
- "openapi": "3.1.0",
- "info": {
- "title": "Loops OpenAPI Spec",
- "description": "This is the OpenAPI Spec for the [Loops API](https://loops.so/docs/api).",
- "version": "1.3.3"
- },
- "servers": [
- {
- "url": "https://app.loops.so/api/v1"
- }
- ],
- "tags": [
- {
- "name": "API key"
- },
- {
- "name": "Contacts",
- "description": "Manage contacts in your audience"
- },
- {
- "name": "Mailing lists",
- "description": "View mailing lists"
- },
- {
- "name": "Events",
- "description": "Trigger email sending with events"
- },
- {
- "name": "Transactional emails",
- "description": "Send transactional emails"
- },
- {
- "name": "Custom fields",
- "description": "View custom contact properties"
- }
- ],
- "paths": {
- "/api-key": {
- "get": {
- "tags": [
- "API key"
- ],
- "summary": "Test your API key",
- "responses": {
- "200": {
- "description": "Success",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- true
- ]
- },
- "teamName": {
- "type": "string",
- "description": "The name of the team the API key belongs to.",
- "examples": [
- "Company name"
- ]
- }
- },
- "required": [
- "success",
- "teamName"
- ]
- }
- }
- }
- },
- "401": {
- "description": "Invalid API key",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "error": {
- "type": "string",
- "examples": [
- "Invalid API key"
- ]
- }
- }
- }
- }
- }
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/contacts/create": {
- "post": {
- "tags": [
- "Contacts"
- ],
- "summary": "Create a contact",
- "description": "Add a contact to your audience.",
- "requestBody": {
- "description": "You can add custom contact properties as keys in this request (of type `string`, `number`, `boolean` or `date` ([see available date formats](https://loops.so/docs/contacts/properties#dates))).
Make sure to create the properties in Loops before using them in API calls.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Successful create.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactSuccessResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. invalid email address).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "409": {
- "description": "Email or `userId` already exists.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/contacts/update": {
- "put": {
- "tags": [
- "Contacts"
- ],
- "summary": "Update a contact",
- "description": "Update a contact by `email` or `userId`.
If you want to update a contact’s email address, the contact will first need a `userId` value. You can then make a request containing the userId field along with an updated email address.",
- "requestBody": {
- "description": "You can add custom contact properties as keys in this request (of type `string`, `number`, `boolean` or `date` ([see available date formats](https://loops.so/docs/contacts/properties#dates))).
Make sure to create the properties in Loops before using them in API calls.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Successful update.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactSuccessResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. `email` or `userId` are missing).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/contacts/find": {
- "get": {
- "tags": [
- "Contacts"
- ],
- "summary": "Find a contact",
- "description": "Search for a contact by `email` or `userId`. Only one parameter is allowed.",
- "parameters": [
- {
- "name": "email",
- "in": "query",
- "required": false,
- "description": "Email address (URI-encoded)",
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "userId",
- "in": "query",
- "required": false,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "List of contacts (or an empty array if no contact was found). Contact objects will include any custom properties.",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Contact"
- }
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. invalid email address).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/contacts/delete": {
- "post": {
- "tags": [
- "Contacts"
- ],
- "summary": "Delete a contact",
- "description": "Delete a contact by `email` or `userId`.",
- "requestBody": {
- "description": "Include only one of `email` or `userId`.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactDeleteRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Successful delete.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactDeleteResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. `email` and `userId` are both provided).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "404": {
- "description": "Contact not found.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ContactFailureResponse"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/lists": {
- "get": {
- "tags": [
- "Mailing lists"
- ],
- "summary": "Get a list of mailing lists",
- "description": "Retrieve a list of your account's mailing lists.",
- "responses": {
- "200": {
- "description": "Successful.",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/MailingList"
- }
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/events/send": {
- "post": {
- "tags": [
- "Events"
- ],
- "summary": "Send an event",
- "description": "Send events to trigger emails in Loops.",
- "requestBody": {
- "description": "Provide either `email` or `userId` to identify the contact ([read more](https://loops.so/docs/api-reference/send-event#body)).
You can add event properties, which will be available in emails sent by this event. Values can be of type string, number, boolean or date ([see allowed date formats](https://loops.so/docs/events/properties#important-information-about-event-properties)).
Make sure to create the properties in Loops before using them in API calls.
You can add contact properties as keys in this request (of type `string`, `number`, `boolean` or `date` ([see available date formats](https://loops.so/docs/contacts/properties#dates))).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/EventRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Successful send.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/EventSuccessResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. `eventName` is missing).",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/EventFailureResponse"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/transactional": {
- "post": {
- "tags": [
- "Transactional emails"
- ],
- "summary": "Send a transactional email",
- "description": "Send a transactional email to a contact.
Please [email us](mailto:help@loops.so) to enable attachments on your account before using them with the API.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/TransactionalRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "Successful send.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/TransactionalSuccessResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad request (e.g. transactional email is not published).",
- "content": {
- "application/json": {
- "schema": {
- "oneOf": [
- {
- "$ref": "#/components/schemas/TransactionalFailureResponse"
- },
- {
- "$ref": "#/components/schemas/TransactionalFailure2Response"
- },
- {
- "$ref": "#/components/schemas/TransactionalFailure3Response"
- }
- ]
- }
- }
- }
- },
- "404": {
- "description": "Transactional email not found.",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/TransactionalFailure2Response"
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- },
- "/contacts/customFields": {
- "get": {
- "tags": [
- "Custom fields"
- ],
- "summary": "Get a list of custom contact properties",
- "description": "Retrieve a list of your account's custom contact properties.",
- "responses": {
- "200": {
- "description": "Successful.",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/CustomField"
- }
- }
- }
- }
- },
- "405": {
- "description": "Wrong HTTP request method."
- }
- },
- "security": [
- {
- "apiKey": []
- }
- ]
- }
- }
- },
- "components": {
- "schemas": {
- "Contact": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "email": {
- "type": "string"
- },
- "firstName": {
- "type": "string"
- },
- "lastName": {
- "type": "string"
- },
- "source": {
- "type": "string"
- },
- "subscribed": {
- "type": "boolean"
- },
- "userGroup": {
- "type": "string"
- },
- "userId": {
- "type": "string"
- },
- "mailingLists": {
- "type": "object",
- "description": "An object of mailing list IDs and boolean subscription statuses.",
- "examples": [
- {
- "list_123": true
- }
- ]
- }
- }
- },
- "ContactRequest": {
- "type": "object",
- "required": [
- "email"
- ],
- "properties": {
- "email": {
- "type": "string"
- },
- "firstName": {
- "type": "string"
- },
- "lastName": {
- "type": "string"
- },
- "subscribed": {
- "type": "boolean"
- },
- "userGroup": {
- "type": "string"
- },
- "userId": {
- "type": "string"
- },
- "mailingLists": {
- "type": "object",
- "description": "An object of mailing list IDs and boolean subscription statuses.",
- "examples": [
- {
- "list_123": true
- }
- ]
- }
- }
- },
- "ContactSuccessResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- true
- ]
- },
- "id": {
- "type": "string"
- }
- },
- "required": [
- "success",
- "id"
- ]
- },
- "ContactFailureResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "message": {
- "type": "string"
- }
- },
- "required": [
- "success",
- "message"
- ]
- },
- "ContactDeleteRequest": {
- "type": "object",
- "properties": {
- "email": {
- "type": "string"
- },
- "userId": {
- "type": "string"
- }
- },
- "required": [
- "email",
- "userId"
- ]
- },
- "ContactDeleteResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- true
- ]
- },
- "message": {
- "type": "string",
- "examples": [
- "Contact deleted."
- ]
- }
- },
- "required": [
- "success",
- "message"
- ]
- },
- "EventRequest": {
- "type": "object",
- "required": [
- "eventName"
- ],
- "properties": {
- "email": {
- "type": "string"
- },
- "userId": {
- "type": "string"
- },
- "eventName": {
- "type": "string"
- },
- "eventProperties": {
- "type": "object",
- "description": "An object containing event property data for the event, available in emails sent by the event."
- },
- "mailingLists": {
- "type": "object",
- "description": "An object of mailing list IDs and boolean subscription statuses.",
- "examples": [
- {
- "list_123": true
- }
- ]
- }
- }
- },
- "EventSuccessResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- true
- ]
- }
- },
- "required": [
- "success"
- ]
- },
- "EventFailureResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "message": {
- "type": "string"
- }
- },
- "required": [
- "success",
- "message"
- ]
- },
- "TransactionalRequest": {
- "type": "object",
- "required": [
- "email",
- "transactionalId"
- ],
- "properties": {
- "email": {
- "type": "string"
- },
- "transactionalId": {
- "type": "string",
- "description": "The ID of the transactional email to send."
- },
- "addToAudience": {
- "type": "boolean",
- "description": "If `true`, a contact will be created in your audience using the `email` value (if a matching contact doesn't already exist)."
- },
- "dataVariables": {
- "type": "object",
- "description": "An object containing contact data as defined by the data variables added to the transactional email template.",
- "examples": [
- {
- "name": "Chris",
- "passwordResetLink": "https://example.com/reset-password"
- }
- ]
- },
- "attachments": {
- "type": "array",
- "description": "A list containing file objects to be sent along with an email message.",
- "items": {
- "type": "object",
- "required": [
- "filename",
- "contentType",
- "data"
- ],
- "properties": {
- "filename": {
- "type": "string",
- "description": "The name of the file, shown in email clients."
- },
- "contentType": {
- "type": "string",
- "description": "The MIME type of the file."
- },
- "data": {
- "type": "string",
- "description": "The base64-encoded content of the file."
- }
- }
- }
- }
- }
- },
- "TransactionalSuccessResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- true
- ]
- }
- },
- "required": [
- "success"
- ]
- },
- "TransactionalFailureResponse": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "path": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- },
- "required": [
- "success",
- "path",
- "message"
- ]
- },
- "TransactionalFailure2Response": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "error": {
- "type": "object",
- "properties": {
- "path": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- }
- }
- },
- "required": [
- "success",
- "error"
- ]
- },
- "TransactionalFailure3Response": {
- "type": "object",
- "properties": {
- "success": {
- "type": "boolean",
- "examples": [
- false
- ]
- },
- "message": {
- "type": "string"
- }
- },
- "required": [
- "success",
- "message"
- ]
- },
- "CustomField": {
- "type": "object",
- "properties": {
- "key": {
- "type": "string"
- },
- "label": {
- "type": "string"
- },
- "type": {
- "type": "string"
- }
- },
- "examples": [
- {
- "key": "favoriteColor",
- "label": "Favorite color",
- "type": "string"
- }
- ],
- "required": [
- "key",
- "label",
- "type"
- ]
- },
- "MailingList": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "isPublic": {
- "type": "boolean"
- }
- },
- "examples": [
- {
- "id": "list_123",
- "name": "Main mailing list",
- "isPublic": true
- }
- ],
- "required": [
- "id",
- "name",
- "isPublic"
- ]
- }
- },
- "securitySchemes": {
- "apiKey": {
- "type": "http",
- "scheme": "bearer"
- }
- }
- }
-}
\ No newline at end of file