2026-04-16 22:41:43 +00:00
|
|
|
package lob
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"crypto/tls"
|
|
|
|
|
"fmt"
|
2026-04-17 02:22:05 +00:00
|
|
|
"io"
|
2026-04-16 22:41:43 +00:00
|
|
|
"os"
|
|
|
|
|
|
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
"resty.dev/v3"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Lob struct {
|
|
|
|
|
APIKey string
|
|
|
|
|
|
|
|
|
|
client *resty.Client
|
|
|
|
|
urlBaseApi string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewLob(api_key string) *Lob {
|
|
|
|
|
r := resty.New()
|
|
|
|
|
if os.Getenv("LOB_INSECURE_SKIP_VERIFY") != "" {
|
|
|
|
|
log.Warn().Msg("Using insecure TLS verification settings")
|
|
|
|
|
r.SetTLSClientConfig(&tls.Config{
|
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
r.SetBasicAuth(api_key, "")
|
|
|
|
|
l := &Lob{
|
|
|
|
|
APIKey: api_key,
|
|
|
|
|
client: r,
|
|
|
|
|
urlBaseApi: "api.lob.com",
|
|
|
|
|
}
|
|
|
|
|
return l
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 00:02:10 +00:00
|
|
|
type Address struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Company string `json:"company"`
|
|
|
|
|
Phone *string `json:"phone"`
|
|
|
|
|
Email *string `json:"email"`
|
|
|
|
|
AddressLine1 string `json:"address_line1"`
|
|
|
|
|
AddressLine2 *string `json:"address_line2"`
|
|
|
|
|
AddressCity string `json:"address_city"`
|
|
|
|
|
AddressState string `json:"address_state"`
|
|
|
|
|
AddressZip string `json:"address_zip"`
|
|
|
|
|
AddressCountry string `json:"address_country"`
|
|
|
|
|
Metadata map[string]interface{} `json:"metadata"`
|
|
|
|
|
DateCreated string `json:"date_created"`
|
|
|
|
|
DateModified string `json:"date_modified"`
|
|
|
|
|
RecipientMoved bool `json:"recipient_moved"`
|
|
|
|
|
Object string `json:"object"`
|
|
|
|
|
}
|
2026-04-17 01:00:16 +00:00
|
|
|
type Letter struct {
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Metadata map[string]interface{} `json:"metadata"`
|
|
|
|
|
To Address `json:"to"`
|
|
|
|
|
From Address `json:"from"`
|
|
|
|
|
Color bool `json:"color"`
|
|
|
|
|
DoubleSided bool `json:"double_sided"`
|
|
|
|
|
AddressPlacement string `json:"address_placement"`
|
|
|
|
|
ReturnEnvelope bool `json:"return_envelope"`
|
|
|
|
|
PerforatedPage *int `json:"perforated_page"`
|
|
|
|
|
ExtraService string `json:"extra_service"`
|
|
|
|
|
CustomEnvelope *string `json:"custom_envelope"`
|
|
|
|
|
TemplateID string `json:"template_id"`
|
|
|
|
|
TemplateVersionID string `json:"template_version_id"`
|
|
|
|
|
MailType string `json:"mail_type"`
|
|
|
|
|
URL string `json:"url"`
|
|
|
|
|
MergeVariables map[string]interface{} `json:"merge_variables"`
|
|
|
|
|
Carrier string `json:"carrier"`
|
|
|
|
|
TrackingNumber string `json:"tracking_number"`
|
|
|
|
|
TrackingEvents []interface{} `json:"tracking_events"`
|
|
|
|
|
Thumbnails []interface{} `json:"thumbnails"`
|
|
|
|
|
ExpectedDeliveryDate string `json:"expected_delivery_date"`
|
|
|
|
|
DateCreated string `json:"date_created"`
|
|
|
|
|
DateModified string `json:"date_modified"`
|
|
|
|
|
SendDate string `json:"send_date"`
|
|
|
|
|
UseType string `json:"use_type"`
|
|
|
|
|
FSC bool `json:"fsc"`
|
|
|
|
|
Object string `json:"object"`
|
|
|
|
|
}
|
2026-04-16 22:41:43 +00:00
|
|
|
type ResponseAddressList struct {
|
|
|
|
|
Addresses []Address `json:"data"`
|
|
|
|
|
Count int `json:"count"`
|
|
|
|
|
CountTotal int `json:"total_count"`
|
|
|
|
|
}
|
2026-04-17 01:00:16 +00:00
|
|
|
type ResponseLetterList struct {
|
|
|
|
|
Letters []Letter `json:"data"`
|
|
|
|
|
Count int `json:"count"`
|
|
|
|
|
CountTotal int `json:"total_count"`
|
|
|
|
|
}
|
2026-04-16 22:41:43 +00:00
|
|
|
|
2026-04-17 00:23:34 +00:00
|
|
|
type RequestAddressCreate struct {
|
|
|
|
|
AddressLine1 string `json:"address_line1"`
|
|
|
|
|
AddressCity string `json:"address_city"`
|
|
|
|
|
AddressState string `json:"address_state"`
|
|
|
|
|
AddressZip string `json:"address_zip"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
}
|
2026-04-17 01:00:16 +00:00
|
|
|
type RequestLetterCreate struct {
|
2026-04-17 02:22:05 +00:00
|
|
|
Color bool
|
|
|
|
|
From string
|
|
|
|
|
File io.Reader
|
|
|
|
|
To string
|
|
|
|
|
UseType string
|
2026-04-17 01:00:16 +00:00
|
|
|
}
|
2026-04-17 00:23:34 +00:00
|
|
|
|
2026-04-17 22:53:23 +00:00
|
|
|
/*
|
|
|
|
|
{
|
|
|
|
|
"error": {
|
|
|
|
|
"message": "address_zip is required",
|
|
|
|
|
"status_code": 422,
|
|
|
|
|
"code": "invalid"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
type Error struct {
|
|
|
|
|
Code string `json:"code"`
|
|
|
|
|
Message string `json:"message"`
|
|
|
|
|
StatusCode int `json:"status_code"`
|
|
|
|
|
}
|
|
|
|
|
type ResponseError struct {
|
|
|
|
|
InnerError Error `json:"error"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (re ResponseError) Error() string {
|
|
|
|
|
return fmt.Sprintf("%d %s %s", re.InnerError.StatusCode, re.InnerError.Code, re.InnerError.Message)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 00:23:34 +00:00
|
|
|
func (l *Lob) AddressCreate(ctx context.Context, req RequestAddressCreate) (Address, error) {
|
|
|
|
|
var result Address
|
2026-04-17 22:53:23 +00:00
|
|
|
var error_response ResponseError
|
2026-04-17 00:23:34 +00:00
|
|
|
resp, err := l.client.R().
|
|
|
|
|
SetBody(req).
|
|
|
|
|
SetContext(ctx).
|
|
|
|
|
SetContentType("application/json").
|
2026-04-17 22:53:23 +00:00
|
|
|
SetError(&error_response).
|
2026-04-17 00:23:34 +00:00
|
|
|
SetResult(&result).
|
|
|
|
|
SetPathParam("urlBase", l.urlBaseApi).
|
|
|
|
|
Post("https://{urlBase}/v1/addresses")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return result, fmt.Errorf("address list post: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if !resp.IsSuccess() {
|
2026-04-28 22:14:05 +00:00
|
|
|
return result, fmt.Errorf("address create not successful: %w", error_response)
|
2026-04-17 00:23:34 +00:00
|
|
|
}
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
2026-04-17 00:02:10 +00:00
|
|
|
func (l *Lob) AddressList(ctx context.Context) ([]Address, error) {
|
2026-04-16 22:41:43 +00:00
|
|
|
var result ResponseAddressList
|
2026-04-17 22:53:23 +00:00
|
|
|
var error_response ResponseError
|
2026-04-16 22:41:43 +00:00
|
|
|
|
|
|
|
|
resp, err := l.client.R().
|
|
|
|
|
//SetQueryParamsFromValues(query).
|
|
|
|
|
SetContext(ctx).
|
2026-04-17 22:53:23 +00:00
|
|
|
SetError(&error_response).
|
2026-04-16 22:41:43 +00:00
|
|
|
SetResult(&result).
|
|
|
|
|
SetPathParam("urlBase", l.urlBaseApi).
|
|
|
|
|
Get("https://{urlBase}/v1/addresses")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("address list get: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if !resp.IsSuccess() {
|
2026-04-28 22:14:05 +00:00
|
|
|
return nil, fmt.Errorf("address list not successful: %w", error_response)
|
2026-04-16 22:41:43 +00:00
|
|
|
}
|
2026-04-17 00:02:10 +00:00
|
|
|
return result.Addresses, nil
|
2026-04-16 22:41:43 +00:00
|
|
|
}
|
2026-04-17 01:00:16 +00:00
|
|
|
|
|
|
|
|
func (l *Lob) LetterCreate(ctx context.Context, req RequestLetterCreate) (Letter, error) {
|
2026-04-17 22:53:23 +00:00
|
|
|
var error_response ResponseError
|
2026-04-17 01:00:16 +00:00
|
|
|
var result Letter
|
2026-04-17 02:22:05 +00:00
|
|
|
color_str := "false"
|
|
|
|
|
if req.Color {
|
|
|
|
|
color_str = "true"
|
|
|
|
|
}
|
2026-04-17 01:00:16 +00:00
|
|
|
resp, err := l.client.R().
|
2026-04-17 22:53:23 +00:00
|
|
|
SetContext(ctx).
|
|
|
|
|
SetError(&error_response).
|
2026-04-17 02:22:05 +00:00
|
|
|
SetMultipartField(
|
|
|
|
|
"file",
|
|
|
|
|
"content.pdf",
|
|
|
|
|
"application/pdf",
|
|
|
|
|
req.File,
|
|
|
|
|
).
|
|
|
|
|
SetMultipartFormData(map[string]string{
|
|
|
|
|
"color": color_str,
|
|
|
|
|
"from": req.From,
|
|
|
|
|
"to": req.To,
|
|
|
|
|
"use_type": req.UseType,
|
|
|
|
|
}).
|
2026-04-17 01:00:16 +00:00
|
|
|
SetResult(&result).
|
|
|
|
|
SetPathParam("urlBase", l.urlBaseApi).
|
|
|
|
|
Post("https://{urlBase}/v1/letters")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return result, fmt.Errorf("letters list post: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if !resp.IsSuccess() {
|
2026-04-28 22:14:05 +00:00
|
|
|
return result, fmt.Errorf("letter create not successful. %w", error_response)
|
2026-04-17 01:00:16 +00:00
|
|
|
}
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
func (l *Lob) LetterList(ctx context.Context) ([]Letter, error) {
|
2026-04-17 22:53:23 +00:00
|
|
|
var error_response ResponseError
|
2026-04-17 01:00:16 +00:00
|
|
|
var result ResponseLetterList
|
|
|
|
|
|
|
|
|
|
resp, err := l.client.R().
|
|
|
|
|
//SetQueryParamsFromValues(query).
|
|
|
|
|
SetContext(ctx).
|
2026-04-17 22:53:23 +00:00
|
|
|
SetError(&error_response).
|
2026-04-17 01:00:16 +00:00
|
|
|
SetResult(&result).
|
|
|
|
|
SetPathParam("urlBase", l.urlBaseApi).
|
|
|
|
|
Get("https://{urlBase}/v1/letters")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("letter list get: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if !resp.IsSuccess() {
|
2026-04-28 22:14:05 +00:00
|
|
|
return nil, fmt.Errorf("letter list not successful. Error: %w", error_response)
|
2026-04-17 01:00:16 +00:00
|
|
|
}
|
|
|
|
|
return result.Letters, nil
|
|
|
|
|
}
|