Skip to main content

Conversation Overview

Conversations allows you to maintain state and interact with a user over multiple steps without managing complex state machines manually. Gogram provides a robust API to ask questions, wait for input, and handle timeouts.

Starting a Conversation

To start a conversation, you need a NewMessage context (usually from a command or message).
client.On("cmd:start", func(m *telegram.NewMessage) error {
    // Start conversation with 60s timeout
    conv, err := m.Conv(60)
    if err != nil {
        return err
    }
    defer conv.Close() // Always close when done

    // Interactive logic here...
    return nil
})

Input Methods

Simple Text Input

Ask a question and wait for a text response.
// Ask and wait
msg, err := conv.Ask("What is your name?")
if err != nil {
    return err // Handle timeout/error
}
fmt.Println("Name:", msg.Text())

// Send message manually and wait
conv.Respond("How old are you?")
ageMsg, err := conv.GetResponse()

Validator & Retries

Keep asking until the user provides valid input.
age, err := conv.AskNumber("Please enter your age:", 3) // 3 retries
if err != nil {
    conv.Respond("You failed to provide a valid age.")
    return nil
}

Media Input

Wait for specific media types.
// Ask for photo
photoMsg, err := conv.AskPhoto("Please send a selfie 📸")

// Ask for other media
docMsg, err := conv.AskDocument("Send your CV (PDF)")
locMsg, err := conv.AskLocation("Share your location")

Yes/No Questions

Easily handle boolean choices.
ok, err := conv.AskYesNo("Do you accept the terms?")
if ok {
    conv.Respond("Accepted!")
} else {
    conv.Respond("Declined.")
}

Interactive Keyboards

Button Choices

Send options and wait for a button click.
// Simple choice
callback, err := conv.Choice("Pick a color:", []string{"Red", "Blue", "Green"})
if err == nil {
    callback.Answer("You picked " + callback.DataString())
}

// Multi-row choice
callback, err = conv.ChoiceRow("Pick a fruit:", 
    []string{"Apple", "Banana"},
    []string{"Cherry", "Date"},
)

Conversation Wizard 🧙‍♂️

For complex multi-step forms, use the Wizard API.
wizard := conv.Wizard().
    WithProgress("Step %d/%d").
    AllowBack()

// Add steps
wizard.AddStep("name", "What is your name?")
wizard.AddStep("age", "How old are you?", func(m *telegram.NewMessage) bool {
    // Custom validation
    age, _ := strconv.Atoi(m.Text())
    return age > 18
}, "You must be 18+")

// Run the wizard
results, err := wizard.Run()
if err == nil {
    name := results["name"].Text()
    age := results["age"].Text()
    conv.Respond(fmt.Sprintf("Registered: %s (%s)", name, age))
}

Advanced Control

Regex Matching

Wait for a message matching a pattern.
// Wait for email format
emailMsg, err := conv.GetResponseMatching(regexp.MustCompile(`.+@.+\..+`))

Keyword Matching

Wait for message containing specific words.
// Wait for "help" or "support"
helpMsg, err := conv.GetResponseContaining("help", "support")

Custom Context

Pass a custom context for cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()

conv.WithContext(ctx)

Error Handling

ErrorDescription
ErrConversationTimeoutUser didn’t respond in time.
ErrConversationClosedConversation was closed manually.
ErrConversationAbortedUser sent an abort keyword (e.g., “cancel”).
ErrValidationFailedUser failed validation after max retries.
if errors.Is(err, telegram.ErrConversationTimeout) {
    conv.Respond("You took too long! 😴")
}