conversationep

package
v1.1.10 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AddConversationLinkEndpoint

type AddConversationLinkEndpoint struct{}

Links a business record to a conversation, in addition to whatever topic the conversation is anchored to.

A conversation can link any number of records, and each linked record surfaces the conversation when conversations are listed for that record.

type AddConversationLinkRequest

type AddConversationLinkRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// The kind of business record to link.
	ResourceType constants.ObjectType `json:"resource_type" validate:"required"`
	// The id of the business record to link.
	ResourceID string `json:"resource_id" validate:"required"`
}

Request to link a business record to a conversation.

func (*AddConversationLinkRequest) SchemaExample

func (*AddConversationLinkRequest) SchemaExample() any

type ArchiveConversationEndpoint

type ArchiveConversationEndpoint struct{}

Archives a conversation for the whole account rather than just for the caller.

Only an owner or admin of the conversation can archive it, and direct messages cannot be archived. An archived customer-facing case leaves the working support inbox and is returned only by the archived view.

func (*ArchiveConversationEndpoint) Materialize

type ArchiveConversationRequest

type ArchiveConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Archive Conversation action.

type AssignConversationEndpoint

type AssignConversationEndpoint struct{}

Assigns an external customer-service case to an owner — a user or a team — or clears the assignment.

Only customer-facing cases can be assigned; assigning an internal conversation is rejected. The support inbox can then be filtered to a single assignee, or to the cases nobody owns yet.

func (*AssignConversationEndpoint) Materialize

type AssignConversationRequest

type AssignConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// What kind of owner the case is being assigned to.
	//
	// - `account_user`: an individual teammate takes the case.
	// - `account_group`: a team takes the case, so anyone on it can pick it up.
	AssigneeResourceType field.Optional[constants.ConversationAssigneeType] `json:"assignee_resource_type,omitzero"`
	// The owner's id, an `account_user` or `account_group` matching `assignee_resource_type`.
	//
	// Omit this and `assignee_resource_type` to clear the assignment.
	AssigneeResourceID field.Optional[string] `json:"assignee_resource_id,omitzero"`
}

Request to assign a customer-service case to a single owner — a user or a team.

The owner is a polymorphic (`assignee_resource_type`, `assignee_resource_id`) reference; omit both fields to clear the assignment.

func (*AssignConversationRequest) SchemaExample

func (*AssignConversationRequest) SchemaExample() any

type ContactSupportEndpoint

type ContactSupportEndpoint struct{}

Returns the calling customer's support case with the vendor, opening it on first contact.

A customer has exactly one support case, so repeat calls return the same thread rather than opening another. Opening the first case is refused when the vendor has not configured a support route with at least one recipient — check Support Availability before offering the feature. Once the case exists, the vendor's designated support staff are seated in it so the customer's first message reaches someone.

func (*ContactSupportEndpoint) Materialize

type ContactSupportRequest

type ContactSupportRequest struct{}

Request to open (or resume) the calling customer's support conversation.

The customer is derived from the authenticated relation actor.

type ConversationSvc

type ConversationSvc interface {
	CreateConversation(ctx context.Context, req *CreateConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	ListConversations(ctx context.Context, req *ListConversationsRequest) (*apiresource.List[apiresource.Conversation], *apierror.APIError)
	GetConversation(ctx context.Context, req *RetrieveConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	ContactSupport(ctx context.Context, req *ContactSupportRequest) (*apiresource.Conversation, *apierror.APIError)
	SupportAvailability(ctx context.Context, req *SupportAvailabilityRequest) (*apiresource.SupportAvailability, *apierror.APIError)
	MarkConversationRead(ctx context.Context, req *MarkConversationReadRequest) (*apiresource.Conversation, *apierror.APIError)
	UpdateConversation(ctx context.Context, req *UpdateConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	ArchiveConversation(ctx context.Context, req *ArchiveConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	UnarchiveConversation(ctx context.Context, req *UnarchiveConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	LeaveConversation(ctx context.Context, req *LeaveConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	HideConversation(ctx context.Context, req *HideConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	UnhideConversation(ctx context.Context, req *UnhideConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	MuteConversation(ctx context.Context, req *MuteConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	UnmuteConversation(ctx context.Context, req *UnmuteConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	SendTyping(ctx context.Context, req *TypingRequest) (*apiresource.MessageResource, *apierror.APIError)
	SetLegalHold(ctx context.Context, req *SetLegalHoldRequest) (*apiresource.Conversation, *apierror.APIError)
	RedactConversation(ctx context.Context, req *RedactConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	// External customer-service cases: triage, assignment, links, report.
	SetWorkflowStatus(ctx context.Context, req *SetWorkflowStatusRequest) (*apiresource.Conversation, *apierror.APIError)
	AssignConversation(ctx context.Context, req *AssignConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	ReportConversation(ctx context.Context, req *ReportConversationRequest) (*apiresource.Conversation, *apierror.APIError)
	AddConversationLink(ctx context.Context, req *AddConversationLinkRequest) (*apiresource.ConversationLink, *apierror.APIError)
	RemoveConversationLink(ctx context.Context, req *RemoveConversationLinkRequest) (*apiresource.EmptyResource, *apierror.APIError)
	ListConversationLinks(ctx context.Context, req *ListConversationLinksRequest) (*apiresource.List[apiresource.ConversationLink], *apierror.APIError)
}

ConversationSvc backs the conversation endpoints via the notification-service ChatService gRPC client.

func NewConversationSvc

func NewConversationSvc(config *ConversationSvcConfig) ConversationSvc

type ConversationSvcConfig

type ConversationSvcConfig struct {
	// ChatClient (required) is the notification-service ChatService gRPC client.
	ChatClient pb.ChatServiceClient
}

type CreateConversationEndpoint

type CreateConversationEndpoint struct{}

Starts a direct message or group conversation.

Requesting a direct message that already exists returns the existing thread instead of creating a duplicate, and a direct message is refused when either user has blocked the other. Conversation creation is rate limited per user.

func (*CreateConversationEndpoint) Materialize

type CreateConversationRequest

type CreateConversationRequest struct {
	// The kind of conversation to create.
	//
	// - `direct_message`: a 1:1 thread with exactly one other user. Addressing yourself is allowed and gives you a private notes thread.
	// - `group`: a named thread with any number of user and agent members.
	//
	// `system` channels are created by the platform and cannot be requested here.
	Type constants.ConversationType `json:"type" validate:"required"`
	// The other participants to add.
	//
	// For a direct message, exactly one account user. For a group, the members to seed — these can be omitted when `group_id` supplies a roster, or when the conversation is anchored to a topic resource, since a record discussion may start solo and pull people in later.
	//
	// The caller is always a participant and does not need to be listed; on a group they become its owner and every other member seeded at creation is notified.
	ParticipantAccountUserIDs []string `json:"participant_account_user_ids,omitzero" validate:"omitempty,dive,required"`
	// Seed a group conversation from a reusable roster.
	//
	// The roster's current members are copied into this conversation (in addition to any `participant_account_user_ids`); the conversation is independent afterward. Ignored for direct messages.
	GroupID field.Optional[string] `json:"group_id,omitzero"`
	// Title for a group conversation.
	//
	// A direct message is identified by its participants rather than by a title.
	Title field.Optional[string] `json:"title,omitzero"`
	// The type of business record to anchor this conversation to.
	//
	// An anchored conversation is returned when conversations are listed for that record, which is how a discussion shows up on an order or invoice.
	TopicResourceType field.Optional[constants.ObjectType] `json:"topic_resource_type,omitzero"`
	// The id of the business record to anchor this conversation to.
	TopicResourceID field.Optional[string] `json:"topic_resource_id,omitzero"`
}

Request to create a conversation.

func (*CreateConversationRequest) SchemaExample

func (*CreateConversationRequest) SchemaExample() any

type HideConversationEndpoint

type HideConversationEndpoint struct{}

Hides a conversation from the caller's own list without affecting other participants.

The caller stays a member and keeps receiving notifications; the conversation simply stops appearing in their list until they unhide it, and new messages do not bring it back on their own. The owner of a conversation cannot hide it.

func (*HideConversationEndpoint) Materialize

type HideConversationRequest

type HideConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Hide Conversation action.

type LeaveConversationEndpoint

type LeaveConversationEndpoint struct{}

Removes the caller from a conversation.

An owner cannot leave — hand ownership to someone else first. Leaving posts a "left the conversation" note to the thread and hides the conversation for the caller, who can still read it back but can no longer post.

func (*LeaveConversationEndpoint) Materialize

type LeaveConversationRequest

type LeaveConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Leave Conversation action.

type ListConversationLinksEndpoint

type ListConversationLinksEndpoint struct{}

Returns the business records linked to a conversation.

Every link is returned in one page. The conversation's primary `topic` anchor is not a link and is not listed here.

type ListConversationLinksRequest

type ListConversationLinksRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request to list a conversation's business-record links.

type ListConversationsEndpoint

type ListConversationsEndpoint struct{}

Returns the caller's conversations, most recently active first.

A customer portal user sees only their own support case with the vendor, and an empty list until they have contacted support.

type ListConversationsRequest

type ListConversationsRequest struct {
	apiresource.PaginationRequest
	// Filter by conversation type.
	Type *constants.ConversationType `query:"type"`
	// Filter by whether the conversation is team-only or customer-facing.
	//
	// - `internal`: threads the customer never sees — direct messages, group threads, and record discussions.
	// - `customer`: external customer-service cases the customer takes part in, from the portal or a bridged email thread.
	Audience *constants.ConversationAudience `query:"audience"`
	// Filter by whether the caller has hidden the conversation from their own list.
	Status *constants.ConversationListStatus `query:"status" default:"active"`
	// Restrict to conversations attached to a business record of this type, together with `topic_resource_id`.
	//
	// Matches both conversations anchored to the record and conversations that merely link it, which is what powers the "discussions on this record" view.
	TopicResourceType *constants.ObjectType `query:"topic_resource_type"`
	// The id of the business record, together with `topic_resource_type`.
	TopicResourceID *string `query:"topic_resource_id"`
	// Filter the support inbox to a single triage lane.
	//
	// - `new`: opened but nobody has triaged it yet.
	// - `open`: actively being worked.
	// - `waiting_internal`: blocked on the internal team.
	// - `waiting_external`: blocked on a reply from the customer.
	// - `needs_approval`: a drafted reply is waiting for a human to approve it.
	// - `resolved`: closed out.
	//
	// The working inbox hides resolved cases unless you ask for this lane explicitly.
	WorkflowStatus *constants.ConversationWorkflowStatus `query:"workflow_status"`
	// Filter the support inbox to cases owned by this assignee, an account user or an account group.
	AssigneeResourceID *string `query:"assignee_resource_id"`
	// Restrict the support inbox to cases nobody has been assigned yet.
	Unassigned bool `query:"unassigned"`
	// Return the archived support inbox instead of the working one.
	//
	// This swaps the view rather than widening it: archived cases are returned and unarchived ones are left out.
	IncludeArchived bool `query:"include_archived"`
}

Request to list the caller's conversations.

Supplying a topic resource returns the conversations anchored to that business record; supplying any case filter (or `audience=customer`) returns the support inbox of external customer-service cases.

type MarkConversationReadEndpoint

type MarkConversationReadEndpoint struct{}

Advances the caller's read position in a conversation and returns it with the recalculated unread count.

Reading also dismisses the caller's outstanding notifications for this conversation, and updates the read receipt the other participants see.

type MarkConversationReadRequest

type MarkConversationReadRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// Mark every message up to and including this sequence number as read.
	//
	// A sequence past the conversation's latest message is clamped to it, and the read position never moves backwards, so replaying an older value is harmless.
	UpToSequence int64 `json:"up_to_sequence" validate:"required"`
}

Request to advance the caller's read cursor in a conversation.

func (*MarkConversationReadRequest) SchemaExample

func (*MarkConversationReadRequest) SchemaExample() any

type MuteConversationEndpoint

type MuteConversationEndpoint struct{}

Mutes a conversation's notifications for the caller only, leaving the other participants unaffected.

While muted the caller gets no notification or email for new messages, though the conversation still accumulates an unread count. A direct @mention pierces the mute and still raises a notification.

func (*MuteConversationEndpoint) Materialize

type MuteConversationRequest

type MuteConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// When the mute expires.
	//
	// Omit to mute indefinitely.
	MutedUntil field.Optional[time.Time] `json:"muted_until,omitzero"`
}

Request to mute a conversation for the caller.

func (*MuteConversationRequest) SchemaExample

func (*MuteConversationRequest) SchemaExample() any

type RedactConversationEndpoint

type RedactConversationEndpoint struct{}

Permanently erases the content of every message in a conversation, for right-to-erasure requests.

Message bodies are cleared and attachments are deleted from storage, leaving the messages behind as an empty audit shell. This cannot be undone, and it is refused while the conversation is under legal hold.

func (*RedactConversationEndpoint) Materialize

type RedactConversationRequest

type RedactConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Redact Conversation action.

type RemoveConversationLinkEndpoint

type RemoveConversationLinkEndpoint struct{}

Removes a business-record link from a conversation.

type RemoveConversationLinkRequest

type RemoveConversationLinkRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// The id of the link to remove.
	LinkID string `path:"link_id" validate:"required"`
}

Request to remove a business-record link from a conversation.

type ReportConversationEndpoint

type ReportConversationEndpoint struct{}

Files an abuse report against a conversation, or against one message within it, and returns the conversation.

Only an active participant can report a conversation. The report is recorded for review and changes nothing about the conversation itself — it is not hidden, muted, or removed.

func (*ReportConversationEndpoint) Materialize

type ReportConversationRequest

type ReportConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// Why the conversation or message is being reported, in free-form text.
	Reason string `json:"reason" validate:"required"`
	// The specific message being reported.
	//
	// Omit to report the conversation as a whole.
	MessageID field.Optional[string] `json:"message_id,omitzero"`
}

Request to report a conversation (optionally a specific message) for abuse.

func (*ReportConversationRequest) SchemaExample

func (*ReportConversationRequest) SchemaExample() any

type RetrieveConversationEndpoint

type RetrieveConversationEndpoint struct{}

Returns a single conversation the caller participates in.

Someone who has left the conversation can still read it back; it comes back marked hidden for them. A team member who opens a customer-facing case they are not yet part of is seated in it as a participant.

type RetrieveConversationRequest

type RetrieveConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request to retrieve a single conversation the caller participates in.

type SetLegalHoldEndpoint

type SetLegalHoldEndpoint struct{}

Places a conversation under legal hold or releases it.

Holding it exempts the conversation from automatic retention purging, and any attempt to redact it is refused until the hold is released.

func (*SetLegalHoldEndpoint) Materialize

type SetLegalHoldRequest

type SetLegalHoldRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// Whether to place the conversation under legal hold or release it.
	//
	// - `held`: the conversation is preserved — exempt from automatic retention purging and from redaction.
	// - `released`: normal retention and redaction apply again.
	LegalHold constants.LegalHoldStatus `json:"legal_hold" validate:"required"`
}

Request to place a conversation under legal hold or release it.

func (*SetLegalHoldRequest) SchemaExample

func (*SetLegalHoldRequest) SchemaExample() any

type SetWorkflowStatusEndpoint

type SetWorkflowStatusEndpoint struct{}

Moves a customer-service case to a triage lane in the support inbox.

Only customer-facing cases have a triage lane; an internal conversation is rejected. The lane also advances on its own as the case progresses — an inbound customer message moves it to `waiting_internal`, a drafted reply to `needs_approval`, and an approved reply to `waiting_external` — so a lane set by hand can be overtaken by later activity.

func (*SetWorkflowStatusEndpoint) Materialize

type SetWorkflowStatusRequest

type SetWorkflowStatusRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// The triage lane to move the case to.
	//
	// - `new`: opened but nobody has triaged it yet.
	// - `open`: actively being worked.
	// - `waiting_internal`: blocked on the internal team.
	// - `waiting_external`: blocked on a reply from the customer.
	// - `needs_approval`: a drafted reply is waiting for a human to approve it.
	// - `resolved`: closed out.
	WorkflowStatus constants.ConversationWorkflowStatus `json:"workflow_status" validate:"required"`
}

Request to set the triage lane of a customer-service case.

func (*SetWorkflowStatusRequest) SchemaExample

func (*SetWorkflowStatusRequest) SchemaExample() any

type SupportAvailabilityEndpoint

type SupportAvailabilityEndpoint struct{}

Reports whether the calling customer can contact support.

`available` is true only when the vendor has configured a support route with at least one recipient. The customer portal gates the contact-support feature on this so customers never open a thread no one is set up to receive.

type SupportAvailabilityRequest

type SupportAvailabilityRequest struct{}

Request to check whether the calling customer can contact support.

The customer is derived from the authenticated relation actor.

type TypingEndpoint

type TypingEndpoint struct{}

Broadcasts an ephemeral "typing" indicator to a conversation's live subscribers.

The signal is not persisted; clients reconcile from message history, never from typing events.

func (*TypingEndpoint) Materialize

type TypingRequest

type TypingRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Send Typing Indicator action.

type UnarchiveConversationEndpoint

type UnarchiveConversationEndpoint struct{}

Returns an archived conversation to the active state for the whole account.

Only an owner or admin of the conversation can unarchive it. An unarchived customer-facing case comes back to the working support inbox, and participants who had separately hidden the conversation still see it hidden until they unhide it themselves.

type UnarchiveConversationRequest

type UnarchiveConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Unarchive Conversation action.

type UnhideConversationEndpoint

type UnhideConversationEndpoint struct{}

Restores a conversation the caller had hidden back to their own list.

func (*UnhideConversationEndpoint) Materialize

type UnhideConversationRequest

type UnhideConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Unhide Conversation action.

type UnmuteConversationEndpoint

type UnmuteConversationEndpoint struct{}

Restores notifications for a conversation the caller had muted.

func (*UnmuteConversationEndpoint) Materialize

type UnmuteConversationRequest

type UnmuteConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
}

Request for the Unmute Conversation action.

type UpdateConversationEndpoint

type UpdateConversationEndpoint struct{}

Renames a group conversation.

Only an owner or admin of the conversation can rename it, and direct messages cannot be renamed.

func (*UpdateConversationEndpoint) Materialize

type UpdateConversationRequest

type UpdateConversationRequest struct {
	// Conversation ID.
	ConversationID string `path:"id" validate:"required"`
	// The group conversation's new display title.
	//
	// Send `null` to clear the title and leave the conversation unnamed.
	Title field.Clearable[string] `json:"title,omitzero"`
}

Request to rename a conversation.

func (*UpdateConversationRequest) SchemaExample

func (*UpdateConversationRequest) SchemaExample() any

Jump to

Keyboard shortcuts

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