mirror of
https://github.com/lukaszraczylo/go-telegram.git
synced 2026-06-05 22:43:59 +00:00
ac7cae8fa7
A fully-generated, strongly-typed Go client for the Telegram Bot API. * 176 methods + 301 types generated from Bot API v10.0 * 1408 auto-generated tests (8 scenarios per method) * Typed unions throughout — no 'any' in the public surface * Pluggable HTTP transport and JSON codec (default goccy/go-json) * Built-in retry middleware honouring Telegram's retry_after * Generic dispatcher with filters and conversation handlers * Self-verifying codegen pipeline (regen → audit → emit → run tests) * 14 example bots covering common patterns
102 lines
3.3 KiB
Go
102 lines
3.3 KiB
Go
// Package main demonstrates the Telegram Payments flow:
|
|
//
|
|
// 1. /buy → bot sends an invoice via sendInvoice
|
|
// 2. User confirms → Telegram sends pre_checkout_query → bot answers ok=true
|
|
// 3. User pays → Telegram sends successful_payment in a Message
|
|
//
|
|
// For testing, use Telegram's test payment provider.
|
|
// Set PAYMENT_PROVIDER_TOKEN to the token from @BotFather (test or live).
|
|
// For Telegram Stars payments, set PAYMENT_PROVIDER_TOKEN="" and CURRENCY="XTR".
|
|
//
|
|
// TELEGRAM_BOT_TOKEN=xxx PAYMENT_PROVIDER_TOKEN=yyy go run ./examples/payments
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/lukaszraczylo/go-telegram/api"
|
|
"github.com/lukaszraczylo/go-telegram/client"
|
|
"github.com/lukaszraczylo/go-telegram/dispatch"
|
|
"github.com/lukaszraczylo/go-telegram/transport"
|
|
)
|
|
|
|
func main() {
|
|
token := os.Getenv("TELEGRAM_BOT_TOKEN")
|
|
if token == "" {
|
|
log.Fatal("TELEGRAM_BOT_TOKEN required")
|
|
}
|
|
providerToken := os.Getenv("PAYMENT_PROVIDER_TOKEN") // empty = Telegram Stars (XTR)
|
|
currency := os.Getenv("CURRENCY")
|
|
if currency == "" {
|
|
currency = "USD"
|
|
}
|
|
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
bot := client.New(token,
|
|
client.WithHTTPClient(client.NewRetryDoer(client.NewDefaultHTTPDoer())),
|
|
)
|
|
|
|
router := dispatch.New(bot)
|
|
|
|
// Step 1: user sends /buy — bot replies with an invoice.
|
|
router.OnCommand("/buy", func(c *dispatch.Context, m *api.Message) error {
|
|
_, err := api.SendInvoice(c.Ctx, c.Bot, &api.SendInvoiceParams{
|
|
ChatID: api.ChatIDFromInt(m.Chat.ID),
|
|
Title: "Premium Widget",
|
|
Description: "A top-quality widget that does absolutely everything.",
|
|
Payload: "widget-purchase-v1",
|
|
ProviderToken: providerToken,
|
|
Currency: currency,
|
|
Prices: []api.LabeledPrice{
|
|
{Label: "Widget", Amount: 199}, // $1.99
|
|
{Label: "Tax", Amount: 20}, // $0.20
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Printf("sendInvoice error: %v", err)
|
|
}
|
|
return err
|
|
})
|
|
|
|
// Step 2: user confirms order — Telegram sends pre_checkout_query.
|
|
// Bot MUST respond within 10 seconds.
|
|
router.OnPreCheckoutQuery(func(c *dispatch.Context, q *api.PreCheckoutQuery) error {
|
|
log.Printf("pre_checkout: id=%s payload=%q total=%d %s from=%d",
|
|
q.ID, q.InvoicePayload, q.TotalAmount, q.Currency, q.From.ID)
|
|
|
|
// Validate the order here (check stock, pricing, etc.).
|
|
// For this demo, always approve.
|
|
_, err := api.AnswerPreCheckoutQuery(c.Ctx, c.Bot, &api.AnswerPreCheckoutQueryParams{
|
|
PreCheckoutQueryID: q.ID,
|
|
Ok: true,
|
|
})
|
|
return err
|
|
})
|
|
|
|
// Step 3: payment completed — Telegram delivers a Message.SuccessfulPayment.
|
|
router.OnMessageFilter(
|
|
func(m *api.Message) bool { return m.SuccessfulPayment != nil },
|
|
func(c *dispatch.Context, m *api.Message) error {
|
|
sp := m.SuccessfulPayment
|
|
log.Printf("payment success: charge_id=%s payload=%q amount=%d %s",
|
|
sp.TelegramPaymentChargeID, sp.InvoicePayload, sp.TotalAmount, sp.Currency)
|
|
_, err := api.SendMessage(c.Ctx, c.Bot, &api.SendMessageParams{
|
|
ChatID: api.ChatIDFromInt(m.Chat.ID),
|
|
Text: "Payment received! Your widget is on its way.",
|
|
})
|
|
return err
|
|
},
|
|
)
|
|
|
|
poller := transport.NewLongPoller(bot)
|
|
if err := router.Run(ctx, poller); err != nil && err != context.Canceled {
|
|
log.Printf("router exited: %v", err)
|
|
}
|
|
}
|