lunogram

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

Lunogram Go SDK

Go Reference

Go client library for the Lunogram Client API. Manage user profiles, organizations, events, inbox messages, and scheduled resources from any Go application.

Installation

go get github.com/lunogram/go-sdk

Requires Go 1.22 or later.

Project scoping

Every Client API request is scoped to a single Lunogram project. You supply the project ID (a UUID) once, when constructing the client, and the SDK injects it into every request path automatically — you never pass it per call. Requests are issued under /api/client/projects/{projectID}/....

NewClient validates the project ID and returns an error if it is empty or not a valid UUID.

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	lunogram "github.com/lunogram/go-sdk"
)

func main() {
	// The project ID (a UUID) scopes every request. It is required.
	client, err := lunogram.NewClient("your-api-key", "your-project-id")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	user, err := client.UpsertUser(ctx, &lunogram.UpsertUserRequest{
		Identifier: []lunogram.ExternalID{
			{ExternalID: "user_123"},
		},
		Email: lunogram.String("jane@example.com"),
		Data: map[string]any{
			"first_name": "Jane",
			"plan":       "pro",
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Upserted user:", user.ID)
}

Client options

All options are passed after the required apiKey and projectID arguments, and NewClient returns (*Client, error).

// Custom base URL (e.g. for self-hosted or staging environments)
client, err := lunogram.NewClient(apiKey, projectID, lunogram.WithBaseURL("https://outreach.internal"))

// Custom HTTP client
client, err := lunogram.NewClient(apiKey, projectID, lunogram.WithHTTPClient(&http.Client{
	Timeout:   10 * time.Second,
	Transport: myTransport,
}))

// Custom timeout (applies to the default HTTP client)
client, err := lunogram.NewClient(apiKey, projectID, lunogram.WithTimeout(10*time.Second))

Users

Upsert a user

Create a new user or update an existing one. Users are matched by their external identifiers.

user, err := client.UpsertUser(ctx, &lunogram.UpsertUserRequest{
	Identifier: []lunogram.ExternalID{
		{ExternalID: "user_123"},
	},
	Email:    lunogram.String("jane@example.com"),
	Phone:    lunogram.String("+31612345678"),
	Timezone: lunogram.String("Europe/Amsterdam"),
	Locale:   lunogram.String("nl-NL"),
	Data: map[string]any{
		"first_name":    "Jane",
		"plan":          "enterprise",
	},
})
Delete a user
err := client.DeleteUser(ctx, &lunogram.DeleteUserRequest{
	Identifier: []lunogram.ExternalID{
		{ExternalID: "user_123"},
	},
})
Post user events

Send events that can trigger journeys or update virtual lists. Events are processed asynchronously.

err := client.PostUserEvents(ctx, []lunogram.Event{
	{
		Name: "purchase_completed",
		Identifier: []lunogram.ExternalID{
			{ExternalID: "user_123"},
		},
		Data: map[string]any{
			"product_id": "prod_789",
			"amount":     99.99,
		},
	},
})

You can also target events at users matching specific data attributes instead of an identifier:

err := client.PostUserEvents(ctx, []lunogram.Event{
	{
		Name:  "feature_announcement",
		Match: map[string]any{"plan": "enterprise"},
		Data:  map[string]any{"feature": "advanced_analytics"},
	},
})

Organizations

Upsert an organization
org, err := client.UpsertOrganization(ctx, &lunogram.UpsertOrganizationRequest{
	Identifier: []lunogram.ExternalID{
		{ExternalID: "org_456"},
	},
	Name: lunogram.String("Acme Corp"),
	Data: map[string]any{
		"industry": "technology",
		"size":     "enterprise",
	},
})
Delete an organization

Deleting an organization also removes all its user memberships.

err := client.DeleteOrganization(ctx, &lunogram.DeleteOrganizationRequest{
	Identifier: []lunogram.ExternalID{
		{ExternalID: "org_456"},
	},
})
Add a user to an organization
err := client.AddOrganizationUser(ctx, &lunogram.OrganizationUserRequest{
	Organization: lunogram.OrganizationRef{
		Identifier: []lunogram.ExternalID{{ExternalID: "org_456"}},
	},
	User: lunogram.UserRef{
		Identifier: []lunogram.ExternalID{{ExternalID: "user_123"}},
	},
	Data: map[string]any{
		"role":       "admin",
		"department": "engineering",
	},
})
Remove a user from an organization
err := client.RemoveOrganizationUser(ctx, &lunogram.RemoveOrganizationUserRequest{
	Organization: lunogram.OrganizationRef{
		Identifier: []lunogram.ExternalID{{ExternalID: "org_456"}},
	},
	User: lunogram.UserRef{
		Identifier: []lunogram.ExternalID{{ExternalID: "user_123"}},
	},
})
Post organization events

Events are processed asynchronously and can trigger journeys for all users in the organization.

err := client.PostOrganizationEvents(ctx, []lunogram.OrganizationEvent{
	{
		Name: "subscription_upgraded",
		Identifier: []lunogram.ExternalID{
			{ExternalID: "org_456"},
		},
		Data: map[string]any{
			"plan":  "enterprise",
			"seats": 100,
		},
	},
})

Inbox

Inbox messages are delivered to users or organizations on a specific channel (email, sms, push, or inbox). Creating, reading, and archiving messages are processed asynchronously; querying and counting return immediately.

Create user inbox messages

Identifier is the message's own external identifier, used for idempotency and traceability; Target identifies the recipient.

err := client.PostUserInboxMessages(ctx, []lunogram.InboxMessageCreate{
	{
		Target:     []lunogram.ExternalID{{ExternalID: "user_123"}},
		Identifier: lunogram.ExternalID{ExternalID: "msg_welcome_1"},
		Channel:    lunogram.ChannelInbox,
		Content:    json.RawMessage(`{"title": "Welcome!", "body": "Thanks for joining."}`),
		Tags:       []string{"onboarding"},
	},
})
Query the user inbox

Source, ExternalID, and Channel are required; the remaining fields are optional filters.

list, err := client.GetUserInbox(ctx, &lunogram.InboxQuery{
	Source:     "default",
	ExternalID: "user_123",
	Channel:    lunogram.ChannelInbox,
	Status:     &[]lunogram.InboxStatus{lunogram.InboxStatusUnread}[0],
})
for _, msg := range list.Results {
	fmt.Println(msg.ID, msg.Priority)
}
Count user inbox messages
count, err := client.GetUserInboxCount(ctx, &lunogram.InboxCountQuery{
	Source:     "default",
	ExternalID: "user_123",
	Channel:    lunogram.ChannelInbox,
})
fmt.Printf("%d unread of %d total\n", count.Unread, count.Total)
Mark user messages read or archived
err := client.MarkUserInboxRead(ctx, []lunogram.InboxMessageRef{
	{
		Target:    []lunogram.ExternalID{{ExternalID: "user_123"}},
		MessageID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
	},
})

err = client.MarkUserInboxArchived(ctx, []lunogram.InboxMessageRef{
	{
		Target:    []lunogram.ExternalID{{ExternalID: "user_123"}},
		MessageID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
	},
})
Organization inbox

The organization inbox mirrors the user inbox. Create, query, count, and mark messages with the organization-scoped methods:

err := client.PostOrganizationInboxMessages(ctx, []lunogram.OrganizationInboxMessageCreate{
	{
		Target:     []lunogram.ExternalID{{ExternalID: "org_456"}},
		Identifier: lunogram.ExternalID{ExternalID: "msg_renewal_1"},
		Channel:    lunogram.ChannelInbox,
		Content:    json.RawMessage(`{"title": "Contract renewal"}`),
	},
})

list, err := client.GetOrganizationInbox(ctx, &lunogram.InboxQuery{
	Source:     "default",
	ExternalID: "org_456",
	Channel:    lunogram.ChannelInbox,
})

count, err := client.GetOrganizationInboxCount(ctx, &lunogram.InboxCountQuery{
	Source:     "default",
	ExternalID: "org_456",
	Channel:    lunogram.ChannelInbox,
})

err = client.MarkOrganizationInboxRead(ctx, []lunogram.OrganizationInboxMessageRef{
	{
		Target:    []lunogram.ExternalID{{ExternalID: "org_456"}},
		MessageID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
	},
})

err = client.MarkOrganizationInboxArchived(ctx, []lunogram.OrganizationInboxMessageRef{
	{
		Target:    []lunogram.ExternalID{{ExternalID: "org_456"}},
		MessageID: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
	},
})

Devices and push

Register a device's push subscription for a user, and fetch the project's VAPID public key for Web Push:

os := lunogram.DeviceOSWeb
err := client.RegisterDevice(ctx, &lunogram.DeviceRegistration{
	Identifier: []lunogram.ExternalID{{ExternalID: "user_123"}},
	DeviceID:   "user_123_web",
	OS:         &os,
	Config: lunogram.DeviceConfig{
		Endpoint: lunogram.String("https://push.example.com/subscription"),
		Keys: &lunogram.DeviceKeys{
			P256dh: "BKey-p256dh-value",
			Auth:   "auth-secret",
		},
	},
})

key, err := client.GetVapidPublicKey(ctx)
// key.PublicKey is the project's VAPID public key

Sessions

Mint a short-lived session token for an end user, server-side, so the client can call the Client API directly. The session's permissions are defined by the session auth method (policy) identified by authMethodID:

token, err := client.CreateSession(ctx, "auth-method-uuid", &lunogram.CreateSessionRequest{
	UserID: "user_123",
})
// token.Token is a bearer token for the Client API; token.ExpiresAt is its expiry

Scheduled resources

Scheduled resources trigger journey entrance recalculation at a specific time or on a recurring interval.

User scheduled
// Single schedule
accepted, err := client.UpsertUserScheduled(ctx, &lunogram.UpsertUserScheduledRequest{
	Name: "trial_end",
	Identifier: []lunogram.ExternalID{
		{ExternalID: "user_123"},
	},
	ScheduledAt: &trialEnd, // time.Time
	Data: map[string]any{
		"plan":   "pro",
		"amount": 29.99,
	},
})

// Recurring schedule
accepted, err := client.UpsertUserScheduled(ctx, &lunogram.UpsertUserScheduledRequest{
	Name: "weekly_digest",
	Identifier: []lunogram.ExternalID{
		{ExternalID: "user_123"},
	},
	Interval: lunogram.String("168h"), // weekly
})

// Delete scheduled resource
err := client.DeleteUserScheduled(ctx, &lunogram.DeleteUserScheduledRequest{
	Name: "trial_end",
	Identifier: []lunogram.ExternalID{
		{ExternalID: "user_123"},
	},
})
Organization scheduled
accepted, err := client.UpsertOrganizationScheduled(ctx, &lunogram.UpsertOrganizationScheduledRequest{
	Name: "contract_renewal",
	Identifier: []lunogram.ExternalID{
		{ExternalID: "org_456"},
	},
	ScheduledAt: &renewalDate,
	Data: map[string]any{
		"contract_type": "enterprise",
		"seats":         100,
	},
})

err := client.DeleteOrganizationScheduled(ctx, &lunogram.DeleteOrganizationScheduledRequest{
	Name: "contract_renewal",
	Identifier: []lunogram.ExternalID{
		{ExternalID: "org_456"},
	},
})

Error handling

All methods return an *lunogram.APIError when the API responds with a non-2xx status code. You can inspect it for details:

user, err := client.UpsertUser(ctx, req)
if err != nil {
	var apiErr *lunogram.APIError
	if errors.As(err, &apiErr) {
		fmt.Printf("API error %d: %s — %s\n", apiErr.StatusCode, apiErr.Title, apiErr.Detail)
	}
	return err
}

External identifiers

Many requests accept one or more external identifiers. The Source field defaults to "default" when omitted.

// Simple identifier (source defaults to "default")
lunogram.ExternalID{ExternalID: "user_123"}

// Explicit source
lunogram.ExternalID{Source: "stripe", ExternalID: "cus_abc123"}

// With metadata
lunogram.ExternalID{
	Source:     "hubspot",
	ExternalID: "contact_789",
	Metadata:   map[string]any{"synced": true},
}

License

See LICENSE for details.

Documentation

Overview

Package lunogram provides a Go client for the Lunogram Client API.

Create a client with your API key and project ID, then use it to manage users, organizations, events, and scheduled resources in that project. Every Client API request is scoped to the project supplied at construction; the SDK injects the project into the request path automatically.

client, err := lunogram.NewClient("your-api-key", "your-project-id")
if err != nil {
    // handle invalid project ID
}
user, err := client.UpsertUser(ctx, &lunogram.UpsertUserRequest{...})

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func String

func String(s string) *string

String returns a pointer to s. Use this to set optional string fields on request types.

client.UpsertUser(ctx, &lunogram.UpsertUserRequest{
    Identifier: []lunogram.ExternalID{{ExternalID: "user_1"}},
    Email:      lunogram.String("user@example.com"),
})

Types

type APIError

type APIError struct {
	StatusCode int
	Title      string `json:"title"`
	Detail     string `json:"detail"`
}

APIError is returned when the API responds with a non-success status code.

func (*APIError) Error

func (e *APIError) Error() string

type Channel added in v0.3.0

type Channel string

Channel is the delivery channel of an inbox message.

const (
	ChannelEmail Channel = "email"
	ChannelSMS   Channel = "sms"
	ChannelPush  Channel = "push"
	ChannelInbox Channel = "inbox"
)

Supported delivery channels.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client communicates with the Lunogram Client API.

func NewClient

func NewClient(apiKey, projectID string, opts ...Option) (*Client, error)

NewClient creates a Lunogram client authenticated with the given API key and scoped to the given project. projectID must be a non-empty UUID; every Client API request is issued under /api/client/projects/{projectID}/.

It returns an error if projectID is empty or not a valid UUID.

func (*Client) AddOrganizationUser

func (c *Client) AddOrganizationUser(ctx context.Context, req *OrganizationUserRequest) error

AddOrganizationUser adds a user to an organization with optional organization-specific data (e.g. role, department).

func (*Client) CreateSession added in v0.3.0

func (c *Client) CreateSession(ctx context.Context, authMethodID string, req *CreateSessionRequest) (*SessionToken, error)

CreateSession mints a short-lived session token for an end user, to be used from the client. It is called server-side with an API key; the session's permissions are defined by the session auth method (policy) identified by authMethodID.

func (*Client) DeleteOrganization

func (c *Client) DeleteOrganization(ctx context.Context, req *DeleteOrganizationRequest) error

DeleteOrganization deletes an organization and removes all its memberships.

func (*Client) DeleteOrganizationScheduled

func (c *Client) DeleteOrganizationScheduled(ctx context.Context, req *DeleteOrganizationScheduledRequest) error

DeleteOrganizationScheduled deletes all scheduled instances for an organization with the given resource name. This cancels any pending journey entrance states.

func (*Client) DeleteUser

func (c *Client) DeleteUser(ctx context.Context, req *DeleteUserRequest) error

DeleteUser deletes a user by their external identifier(s).

func (*Client) DeleteUserScheduled

func (c *Client) DeleteUserScheduled(ctx context.Context, req *DeleteUserScheduledRequest) error

DeleteUserScheduled deletes all scheduled instances for a user with the given resource name. This cancels any pending journey entrance states.

func (*Client) GetOrganizationInbox added in v0.3.0

func (c *Client) GetOrganizationInbox(ctx context.Context, query *InboxQuery) (*InboxMessageList, error)

GetOrganizationInbox returns visible, non-expired inbox messages for the organization identified by the query's source and external ID. Source, ExternalID, and Channel are required.

func (*Client) GetOrganizationInboxCount added in v0.3.0

func (c *Client) GetOrganizationInboxCount(ctx context.Context, query *InboxCountQuery) (*InboxCount, error)

GetOrganizationInboxCount returns unread and total visible inbox message counts for the organization identified by the query. Source, ExternalID, and Channel are required.

func (*Client) GetUserInbox added in v0.3.0

func (c *Client) GetUserInbox(ctx context.Context, query *InboxQuery) (*InboxMessageList, error)

GetUserInbox returns visible, non-expired inbox messages for the user identified by the query's source and external ID. Source, ExternalID, and Channel are required.

func (*Client) GetUserInboxCount added in v0.3.0

func (c *Client) GetUserInboxCount(ctx context.Context, query *InboxCountQuery) (*InboxCount, error)

GetUserInboxCount returns unread and total visible inbox message counts for the user identified by the query. Source, ExternalID, and Channel are required.

func (*Client) GetVapidPublicKey added in v0.3.0

func (c *Client) GetVapidPublicKey(ctx context.Context) (*VapidPublicKey, error)

GetVapidPublicKey returns the project's VAPID public key for Web Push.

func (*Client) MarkOrganizationInboxArchived added in v0.3.0

func (c *Client) MarkOrganizationInboxArchived(ctx context.Context, messages []OrganizationInboxMessageRef) error

MarkOrganizationInboxArchived marks one or more organization inbox messages as archived. The events are processed asynchronously.

func (*Client) MarkOrganizationInboxRead added in v0.3.0

func (c *Client) MarkOrganizationInboxRead(ctx context.Context, messages []OrganizationInboxMessageRef) error

MarkOrganizationInboxRead marks one or more organization inbox messages as read. The events are processed asynchronously.

func (*Client) MarkUserInboxArchived added in v0.3.0

func (c *Client) MarkUserInboxArchived(ctx context.Context, messages []InboxMessageRef) error

MarkUserInboxArchived marks one or more user inbox messages as archived. The events are processed asynchronously.

func (*Client) MarkUserInboxRead added in v0.3.0

func (c *Client) MarkUserInboxRead(ctx context.Context, messages []InboxMessageRef) error

MarkUserInboxRead marks one or more user inbox messages as read. The events are processed asynchronously.

func (*Client) PostOrganizationEvents

func (c *Client) PostOrganizationEvents(ctx context.Context, events []OrganizationEvent) error

PostOrganizationEvents sends one or more events for organizations. Events are processed asynchronously and can trigger journeys for all users in the targeted organization(s).

func (*Client) PostOrganizationInboxMessages added in v0.3.0

func (c *Client) PostOrganizationInboxMessages(ctx context.Context, messages []OrganizationInboxMessageCreate) error

PostOrganizationInboxMessages creates one or more inbox messages for organizations. Messages are processed asynchronously.

func (*Client) PostUserEvents

func (c *Client) PostUserEvents(ctx context.Context, events []Event) error

PostUserEvents sends one or more events for users. Events are processed asynchronously and can trigger journeys or update virtual lists.

Each event is handled independently: if one fails, others may still succeed.

func (*Client) PostUserInboxMessages added in v0.3.0

func (c *Client) PostUserInboxMessages(ctx context.Context, messages []InboxMessageCreate) error

PostUserInboxMessages creates one or more inbox messages for users. Messages are processed asynchronously.

func (*Client) RegisterDevice added in v0.3.0

func (c *Client) RegisterDevice(ctx context.Context, req *DeviceRegistration) error

RegisterDevice registers or updates a device's push subscription for a user. The user is identified by the registration's Identifier.

func (*Client) RemoveOrganizationUser

func (c *Client) RemoveOrganizationUser(ctx context.Context, req *RemoveOrganizationUserRequest) error

RemoveOrganizationUser removes a user from an organization.

func (*Client) UpsertOrganization

func (c *Client) UpsertOrganization(ctx context.Context, req *UpsertOrganizationRequest) (*Organization, error)

UpsertOrganization creates or updates an organization by external identifier(s).

func (*Client) UpsertOrganizationScheduled

func (c *Client) UpsertOrganizationScheduled(ctx context.Context, req *UpsertOrganizationScheduledRequest) (*ScheduledAccepted, error)

UpsertOrganizationScheduled creates or updates a scheduled resource for an organization. This triggers journey entrance recalculation for any journeys that depend on the scheduled resource.

func (*Client) UpsertUser

func (c *Client) UpsertUser(ctx context.Context, req *UpsertUserRequest) (*User, error)

UpsertUser creates or updates a user profile. The user is identified by one or more external identifiers. If a user with any of the given identifiers already exists, it is updated; otherwise a new user is created.

func (*Client) UpsertUserScheduled

func (c *Client) UpsertUserScheduled(ctx context.Context, req *UpsertUserScheduledRequest) (*ScheduledAccepted, error)

UpsertUserScheduled creates or updates a scheduled resource for a user. This triggers journey entrance recalculation for any journeys that depend on the scheduled resource.

type CreateSessionRequest added in v0.3.0

type CreateSessionRequest struct {
	// UserID is the end user's external identifier (the session subject).
	UserID string `json:"user_id"`
}

CreateSessionRequest mints a session token for an end user.

type DeleteOrganizationRequest

type DeleteOrganizationRequest struct {
	Identifier []ExternalID `json:"identifier"`
}

DeleteOrganizationRequest deletes an organization by identifier.

type DeleteOrganizationScheduledRequest

type DeleteOrganizationScheduledRequest struct {
	// ID of a single schedule assignment to delete. When set, only that instance
	// is removed; otherwise every assignment matching Name is deleted.
	ID *string `json:"id,omitempty"`

	// Name of the scheduled resource to delete (ignored when ID is set).
	Name string `json:"name,omitempty"`

	// Identifier targets a specific organization.
	Identifier []ExternalID `json:"identifier"`
}

DeleteOrganizationScheduledRequest deletes scheduled instances for an organization. Provide ID to delete a single assignment, or Name to delete every assignment with that name. Identifier is required.

type DeleteUserRequest

type DeleteUserRequest struct {
	Identifier []ExternalID `json:"identifier"`
}

DeleteUserRequest deletes a user by identifier.

type DeleteUserScheduledRequest

type DeleteUserScheduledRequest struct {
	// ID of a single schedule assignment to delete. When set, only that instance
	// is removed; otherwise every assignment matching Name is deleted.
	ID *string `json:"id,omitempty"`

	// Name of the scheduled resource to delete (ignored when ID is set).
	Name string `json:"name,omitempty"`

	// Identifier targets a specific user.
	Identifier []ExternalID `json:"identifier,omitempty"`
}

DeleteUserScheduledRequest deletes scheduled instances for a user. Provide ID to delete a single assignment, or Name to delete every assignment with that name. Identifier is required.

type DeviceConfig added in v0.3.0

type DeviceConfig struct {
	// Token is the device token for FCM or APNs.
	Token *string `json:"token,omitempty"`

	// Endpoint is the Web Push subscription endpoint URL.
	Endpoint *string `json:"endpoint,omitempty"`

	// ExpirationTime is when the subscription expires, if known.
	ExpirationTime *time.Time `json:"expiration_time,omitempty"`

	// Keys holds the Web Push subscription keys.
	Keys *DeviceKeys `json:"keys,omitempty"`
}

DeviceConfig is the transport configuration for a device's push subscription.

type DeviceKeys added in v0.3.0

type DeviceKeys struct {
	P256dh string `json:"p256dh"`
	Auth   string `json:"auth"`
}

DeviceKeys holds the Web Push subscription keys.

type DeviceOS added in v0.3.0

type DeviceOS string

DeviceOS is the operating system a registered device runs on.

const (
	DeviceOSWeb     DeviceOS = "web"
	DeviceOSIOS     DeviceOS = "ios"
	DeviceOSAndroid DeviceOS = "android"
)

Supported device operating systems.

type DeviceRegistration added in v0.3.0

type DeviceRegistration struct {
	// Identifier targets the user the device belongs to.
	Identifier []ExternalID `json:"identifier"`

	// DeviceID is the caller's stable identifier for the device.
	DeviceID string `json:"device_id"`

	// Config is the device's push transport configuration.
	Config DeviceConfig `json:"config"`

	// OS is the device operating system (web, ios, android).
	OS *DeviceOS `json:"os,omitempty"`

	// OSVersion is the device operating system version.
	OSVersion *string `json:"os_version,omitempty"`

	// Model is the device model.
	Model *string `json:"model,omitempty"`

	// AppVersion is the version of the app the device runs.
	AppVersion *string `json:"app_version,omitempty"`

	// Data holds arbitrary device attributes.
	Data json.RawMessage `json:"data,omitempty"`
}

DeviceRegistration registers or updates a device's push subscription for a user.

type Event

type Event struct {
	// Name of the event (e.g. "purchase_completed").
	Name string `json:"name"`

	// Identifier targets a specific user. Mutually exclusive with Match.
	Identifier []ExternalID `json:"identifier,omitempty"`

	// Match is a JSONB containment filter to target users by data attributes.
	// Mutually exclusive with Identifier.
	Match map[string]any `json:"match,omitempty"`

	// Data holds event-specific attributes.
	Data map[string]any `json:"data"`
}

Event represents a user event to be ingested.

type ExternalID

type ExternalID struct {
	// Source of the identifier (e.g. "default", "anonymous", or a custom source).
	// Defaults to "default" if empty.
	Source string `json:"source,omitempty"`

	// ExternalID is the identifier value in the external system.
	ExternalID string `json:"external_id"`

	// Metadata is optional key-value data associated with this identifier.
	Metadata map[string]any `json:"metadata,omitempty"`
}

ExternalID identifies a user or organization by an external system identifier.

type ExternalIDResponse

type ExternalIDResponse struct {
	ID         string         `json:"id"`
	Source     string         `json:"source"`
	ExternalID string         `json:"external_id"`
	Metadata   map[string]any `json:"metadata,omitempty"`
	CreatedAt  time.Time      `json:"created_at"`
	UpdatedAt  time.Time      `json:"updated_at"`
}

ExternalIDResponse is an external identifier as returned in API responses.

type InboxCount added in v0.3.0

type InboxCount struct {
	Unread int `json:"unread"`
	Total  int `json:"total"`
}

InboxCount holds unread and total visible inbox message counts.

type InboxCountQuery added in v0.3.0

type InboxCountQuery struct {
	// Source of the target's external identifier (e.g. "default").
	Source string

	// ExternalID of the target whose inbox is counted.
	ExternalID string

	// Channel restricts the count to a single delivery channel.
	Channel Channel
}

InboxCountQuery holds the filters for counting user or organization inbox messages. All three fields are required by the API.

type InboxMessage added in v0.3.0

type InboxMessage struct {
	ID               string          `json:"id"`
	ProjectID        string          `json:"project_id"`
	UserID           *string         `json:"user_id,omitempty"`
	OrganizationID   *string         `json:"organization_id,omitempty"`
	ExternalID       *string         `json:"external_id,omitempty"`
	Channel          Channel         `json:"channel"`
	SenderIdentityID *string         `json:"sender_identity_id,omitempty"`
	CampaignID       *string         `json:"campaign_id,omitempty"`
	BroadcastID      *string         `json:"broadcast_id,omitempty"`
	Content          json.RawMessage `json:"content"`
	Data             json.RawMessage `json:"data"`
	Tags             []string        `json:"tags"`
	Priority         int16           `json:"priority"`
	Source           *string         `json:"source,omitempty"`
	ScheduledAt      time.Time       `json:"scheduled_at"`
	ExpiresAt        *time.Time      `json:"expires_at,omitempty"`
	ReadAt           *time.Time      `json:"read_at,omitempty"`
	ArchivedAt       *time.Time      `json:"archived_at,omitempty"`
	SentAt           *time.Time      `json:"sent_at,omitempty"`
	CreatedAt        time.Time       `json:"created_at"`
	UpdatedAt        time.Time       `json:"updated_at"`
}

InboxMessage is an inbox message as returned by the API.

type InboxMessageCreate added in v0.3.0

type InboxMessageCreate struct {
	// Target identifies the user the message is delivered to.
	Target []ExternalID `json:"target"`

	// Identifier is the external identifier of the message itself. It is
	// required for idempotency and traceability back to the origin source.
	Identifier ExternalID `json:"identifier"`

	// Channel is the delivery channel (email, sms, push, inbox).
	Channel Channel `json:"channel"`

	// SenderIdentityID is required for email and sms messages. Push uses the
	// project's push provider settings.
	SenderIdentityID *string `json:"sender_identity_id,omitempty"`

	// CampaignID associates the message with a campaign.
	CampaignID *string `json:"campaign_id,omitempty"`

	// BroadcastID associates the message with a broadcast.
	BroadcastID *string `json:"broadcast_id,omitempty"`

	// Content is the channel-specific payload content.
	Content json.RawMessage `json:"content,omitempty"`

	// Data holds arbitrary message attributes.
	Data map[string]any `json:"data,omitempty"`

	// Tags label the message for filtering.
	Tags []string `json:"tags,omitempty"`

	// Priority is a value from 1 to 5. Defaults to 3 when omitted.
	Priority *int16 `json:"priority,omitempty"`

	// Source is an optional origin label for the message.
	Source *string `json:"source,omitempty"`

	// ScheduledAt is when the message should be delivered.
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`

	// ExpiresAt is when the message stops being visible.
	ExpiresAt *time.Time `json:"expires_at,omitempty"`
}

InboxMessageCreate creates a single inbox message for a user.

type InboxMessageList added in v0.3.0

type InboxMessageList struct {
	Results []InboxMessage `json:"results"`
	Total   int            `json:"total"`
	Limit   int            `json:"limit"`
	Offset  int            `json:"offset"`
}

InboxMessageList is a paginated list of inbox messages.

type InboxMessageRef added in v0.3.0

type InboxMessageRef struct {
	// Target identifies the user the message belongs to.
	Target []ExternalID `json:"target"`

	// MessageID is the UUID of the message to mark.
	MessageID string `json:"message_id"`
}

InboxMessageRef references a single user inbox message to mark read or archived.

type InboxQuery added in v0.3.0

type InboxQuery struct {
	// Source of the target's external identifier (e.g. "default").
	Source string

	// ExternalID of the target whose inbox is queried.
	ExternalID string

	// Channel restricts the query to a single delivery channel. Required.
	Channel Channel

	// Status filters by read/archive state when set.
	Status *InboxStatus

	// Tags filters to messages carrying all of the given tags.
	Tags []string

	// MessageSource filters by the message's origin source label when set.
	MessageSource *string

	// Priority filters to messages with the given priority when set.
	Priority *int

	// Limit caps the number of messages returned (1–100, default 20).
	Limit *int

	// Offset skips the given number of messages for pagination.
	Offset *int
}

InboxQuery holds the filters for querying user or organization inbox messages. Source, ExternalID, and Channel are required by the API; the remaining fields are optional filters.

type InboxStatus added in v0.3.0

type InboxStatus string

InboxStatus filters inbox messages by their read/archive state.

const (
	InboxStatusUnread   InboxStatus = "unread"
	InboxStatusRead     InboxStatus = "read"
	InboxStatusArchived InboxStatus = "archived"
)

Inbox message statuses.

type Option

type Option func(*Client)

Option configures the Client.

func WithBaseURL

func WithBaseURL(url string) Option

WithBaseURL overrides the default API base URL.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient sets a custom http.Client for requests.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the HTTP client timeout. Ignored if WithHTTPClient is also used.

type Organization

type Organization struct {
	ID         string               `json:"id"`
	ProjectID  string               `json:"project_id"`
	Identifier []ExternalIDResponse `json:"identifier"`
	Name       string               `json:"name,omitempty"`
	Data       map[string]any       `json:"data"`
	Version    int32                `json:"version"`
	CreatedAt  time.Time            `json:"created_at"`
	UpdatedAt  time.Time            `json:"updated_at"`
}

Organization represents an organization in Lunogram.

type OrganizationEvent

type OrganizationEvent struct {
	// Name of the event (e.g. "subscription_upgraded").
	Name string `json:"name"`

	// Identifier targets a specific organization. Mutually exclusive with Match.
	Identifier []ExternalID `json:"identifier,omitempty"`

	// Match is a JSONB containment filter to target organizations by data attributes.
	// Mutually exclusive with Identifier.
	Match map[string]any `json:"match,omitempty"`

	// Data holds event-specific attributes.
	Data map[string]any `json:"data,omitempty"`
}

OrganizationEvent represents an organization event to be ingested.

type OrganizationInboxMessageCreate added in v0.3.0

type OrganizationInboxMessageCreate struct {
	// Target identifies the organization the message is delivered to.
	Target []ExternalID `json:"target"`

	// Identifier is the external identifier of the message itself. It is
	// required for idempotency and traceability back to the origin source.
	Identifier ExternalID `json:"identifier"`

	// Channel is the delivery channel (email, sms, push, inbox).
	Channel Channel `json:"channel"`

	// SenderIdentityID is required for email and sms messages. Push uses the
	// project's push provider settings.
	SenderIdentityID *string `json:"sender_identity_id,omitempty"`

	// CampaignID associates the message with a campaign.
	CampaignID *string `json:"campaign_id,omitempty"`

	// BroadcastID associates the message with a broadcast.
	BroadcastID *string `json:"broadcast_id,omitempty"`

	// Content is the channel-specific payload content.
	Content json.RawMessage `json:"content,omitempty"`

	// Data holds arbitrary message attributes.
	Data map[string]any `json:"data,omitempty"`

	// Tags label the message for filtering.
	Tags []string `json:"tags,omitempty"`

	// Priority is a value from 1 to 5. Defaults to 3 when omitted.
	Priority *int16 `json:"priority,omitempty"`

	// Source is an optional origin label for the message.
	Source *string `json:"source,omitempty"`

	// ScheduledAt is when the message should be delivered.
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`

	// ExpiresAt is when the message stops being visible.
	ExpiresAt *time.Time `json:"expires_at,omitempty"`
}

OrganizationInboxMessageCreate creates a single inbox message for an organization.

type OrganizationInboxMessageRef added in v0.3.0

type OrganizationInboxMessageRef struct {
	// Target identifies the organization the message belongs to.
	Target []ExternalID `json:"target"`

	// MessageID is the UUID of the message to mark.
	MessageID string `json:"message_id"`
}

OrganizationInboxMessageRef references a single organization inbox message to mark read or archived.

type OrganizationRef

type OrganizationRef struct {
	Identifier []ExternalID `json:"identifier"`
}

OrganizationRef identifies an organization by its external identifiers.

type OrganizationUserRequest

type OrganizationUserRequest struct {
	Organization OrganizationRef `json:"organization"`
	User         UserRef         `json:"user"`

	// Data holds organization-specific attributes for this user (e.g. role, department).
	Data map[string]any `json:"data,omitempty"`
}

OrganizationUserRequest adds a user to an organization.

type RemoveOrganizationUserRequest

type RemoveOrganizationUserRequest struct {
	Organization OrganizationRef `json:"organization"`
	User         UserRef         `json:"user"`
}

RemoveOrganizationUserRequest removes a user from an organization.

type ScheduledAccepted

type ScheduledAccepted struct {
	ID          string         `json:"id"`
	Name        string         `json:"name"`
	ScheduledAt time.Time      `json:"scheduled_at"`
	Data        map[string]any `json:"data,omitempty"`
}

ScheduledAccepted is returned when a scheduled resource is accepted for processing.

type SessionToken added in v0.3.0

type SessionToken struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expires_at"`
}

SessionToken is a minted session token: a short-lived bearer token for the Client API whose permissions are defined by the session auth method (policy).

type UpsertOrganizationRequest

type UpsertOrganizationRequest struct {
	Identifier []ExternalID   `json:"identifier"`
	Name       *string        `json:"name,omitempty"`
	Data       map[string]any `json:"data,omitempty"`
}

UpsertOrganizationRequest creates or updates an organization.

type UpsertOrganizationScheduledRequest

type UpsertOrganizationScheduledRequest struct {
	// ID of an existing schedule assignment to update in place. Omit to create a
	// new assignment; the same name may be scheduled multiple times. The id is
	// returned in the response.
	ID *string `json:"id,omitempty"`

	// Name of the scheduled resource (e.g. "contract_renewal").
	Name string `json:"name"`

	// Identifier targets a specific organization.
	Identifier []ExternalID `json:"identifier"`

	// ScheduledAt is the trigger time for single schedules.
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`

	// StartAt is the start time for recurring schedules. Defaults to now if omitted.
	StartAt *time.Time `json:"start_at,omitempty"`

	// Interval for recurring schedules (e.g. "24h"). When set, the schedule becomes recurring.
	Interval *string `json:"interval,omitempty"`

	// Data holds scheduled resource attributes.
	Data map[string]any `json:"data,omitempty"`
}

UpsertOrganizationScheduledRequest creates or updates a scheduled resource for an organization.

type UpsertUserRequest

type UpsertUserRequest struct {
	// Identifier contains one or more external identifiers for the user.
	Identifier []ExternalID `json:"identifier"`

	// Email address of the user.
	Email *string `json:"email,omitempty"`

	// Phone number in E.164 format (e.g. "+31612345678").
	Phone *string `json:"phone,omitempty"`

	// Timezone in IANA format (e.g. "Europe/Amsterdam").
	Timezone *string `json:"timezone,omitempty"`

	// Locale as a BCP 47 tag (e.g. "nl-NL").
	Locale *string `json:"locale,omitempty"`

	// Data holds arbitrary user attributes.
	Data map[string]any `json:"data,omitempty"`
}

UpsertUserRequest creates or updates a user profile.

type UpsertUserScheduledRequest

type UpsertUserScheduledRequest struct {
	// ID of an existing schedule assignment to update in place. Omit to create a
	// new assignment; the same name may be scheduled multiple times. The id is
	// returned in the response.
	ID *string `json:"id,omitempty"`

	// Name of the scheduled resource (e.g. "renewal_date").
	Name string `json:"name"`

	// Identifier targets a specific user.
	Identifier []ExternalID `json:"identifier,omitempty"`

	// ScheduledAt is the trigger time for single schedules.
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`

	// StartAt is the start time for recurring schedules. Defaults to now if omitted.
	StartAt *time.Time `json:"start_at,omitempty"`

	// Interval for recurring schedules (e.g. "24h"). When set, the schedule becomes recurring.
	Interval *string `json:"interval,omitempty"`

	// Data holds scheduled resource attributes.
	Data map[string]any `json:"data,omitempty"`
}

UpsertUserScheduledRequest creates or updates a scheduled resource for a user.

type User

type User struct {
	ID            string               `json:"id"`
	ProjectID     string               `json:"project_id"`
	Identifier    []ExternalIDResponse `json:"identifier"`
	Email         string               `json:"email,omitempty"`
	Phone         string               `json:"phone,omitempty"`
	Data          map[string]any       `json:"data"`
	Timezone      string               `json:"timezone,omitempty"`
	Locale        string               `json:"locale,omitempty"`
	HasPushDevice bool                 `json:"has_push_device"`
	Version       int32                `json:"version"`
	CreatedAt     time.Time            `json:"created_at"`
	UpdatedAt     time.Time            `json:"updated_at"`
}

User represents a user profile in Lunogram.

type UserRef

type UserRef struct {
	Identifier []ExternalID `json:"identifier"`
}

UserRef identifies a user by its external identifiers.

type VapidPublicKey added in v0.3.0

type VapidPublicKey struct {
	PublicKey string `json:"public_key"`
}

VapidPublicKey is the project's VAPID public key for Web Push.

Directories

Path Synopsis
Package gen provides primitives to interact with the openapi HTTP API.
Package gen provides primitives to interact with the openapi HTTP API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL