# client
```go
import "github.com/lukaszraczylo/go-telegram/client"
```
Package client provides HTTP client primitives for the Telegram Bot API.
## Index
- [Variables](<#variables>)
- [func Call\[Req any, Resp any\]\(ctx context.Context, b \*Bot, method string, req Req\) \(Resp, error\)](<#Call>)
- [func CallRaw\[Req any\]\(ctx context.Context, b \*Bot, method string, req Req\) \(json.RawMessage, error\)](<#CallRaw>)
- [func NewDefaultHTTPDoer\(\) \*http.Client](<#NewDefaultHTTPDoer>)
- [type APIError](<#APIError>)
- [func \(e \*APIError\) Error\(\) string](<#APIError.Error>)
- [func \(e \*APIError\) IsRetryable\(\) bool](<#APIError.IsRetryable>)
- [func \(e \*APIError\) RetryAfter\(\) time.Duration](<#APIError.RetryAfter>)
- [func \(e \*APIError\) Unwrap\(\) error](<#APIError.Unwrap>)
- [type BodyEncoder](<#BodyEncoder>)
- [type Bot](<#Bot>)
- [func New\(token string, opts ...Option\) \*Bot](<#New>)
- [func \(b \*Bot\) BaseURL\(\) string](<#Bot.BaseURL>)
- [func \(b \*Bot\) Codec\(\) Codec](<#Bot.Codec>)
- [func \(b \*Bot\) HTTP\(\) HTTPDoer](<#Bot.HTTP>)
- [func \(b \*Bot\) Logger\(\) Logger](<#Bot.Logger>)
- [func \(b \*Bot\) Token\(\) string](<#Bot.Token>)
- [type Codec](<#Codec>)
- [type DefaultCodec](<#DefaultCodec>)
- [func \(DefaultCodec\) Marshal\(v any\) \(\[\]byte, error\)](<#DefaultCodec.Marshal>)
- [func \(DefaultCodec\) MarshalTo\(w io.Writer, v any\) error](<#DefaultCodec.MarshalTo>)
- [func \(DefaultCodec\) Unmarshal\(data \[\]byte, v any\) error](<#DefaultCodec.Unmarshal>)
- [type FastHTTPDoer](<#FastHTTPDoer>)
- [func NewFastHTTPDoer\(opts ...FastHTTPDoerOption\) \*FastHTTPDoer](<#NewFastHTTPDoer>)
- [func \(d \*FastHTTPDoer\) Do\(req \*http.Request\) \(\*http.Response, error\)](<#FastHTTPDoer.Do>)
- [type FastHTTPDoerOption](<#FastHTTPDoerOption>)
- [func WithFastHTTPClient\(c \*fasthttp.Client\) FastHTTPDoerOption](<#WithFastHTTPClient>)
- [func WithFastHTTPReadTimeout\(t time.Duration\) FastHTTPDoerOption](<#WithFastHTTPReadTimeout>)
- [type HTTPDoer](<#HTTPDoer>)
- [type Logger](<#Logger>)
- [type MultipartFile](<#MultipartFile>)
- [type NetworkError](<#NetworkError>)
- [func \(e \*NetworkError\) Error\(\) string](<#NetworkError.Error>)
- [func \(e \*NetworkError\) Unwrap\(\) error](<#NetworkError.Unwrap>)
- [type NoopLogger](<#NoopLogger>)
- [func \(NoopLogger\) Debug\(string, ...any\)](<#NoopLogger.Debug>)
- [func \(NoopLogger\) Error\(string, ...any\)](<#NoopLogger.Error>)
- [func \(NoopLogger\) Info\(string, ...any\)](<#NoopLogger.Info>)
- [func \(NoopLogger\) Warn\(string, ...any\)](<#NoopLogger.Warn>)
- [type Option](<#Option>)
- [func WithBaseURL\(url string\) Option](<#WithBaseURL>)
- [func WithCodec\(c Codec\) Option](<#WithCodec>)
- [func WithHTTPClient\(c HTTPDoer\) Option](<#WithHTTPClient>)
- [func WithLogger\(l Logger\) Option](<#WithLogger>)
- [type ParseError](<#ParseError>)
- [func \(e \*ParseError\) Error\(\) string](<#ParseError.Error>)
- [func \(e \*ParseError\) Unwrap\(\) error](<#ParseError.Unwrap>)
- [type ResponseParameters](<#ResponseParameters>)
- [type Result](<#Result>)
- [type RetryDoer](<#RetryDoer>)
- [func NewRetryDoer\(inner HTTPDoer, opts ...RetryOption\) \*RetryDoer](<#NewRetryDoer>)
- [func \(d \*RetryDoer\) Do\(req \*http.Request\) \(\*http.Response, error\)](<#RetryDoer.Do>)
- [type RetryOption](<#RetryOption>)
- [func WithBackoffFactor\(f float64\) RetryOption](<#WithBackoffFactor>)
- [func WithBaseBackoff\(d time.Duration\) RetryOption](<#WithBaseBackoff>)
- [func WithJitter\(j float64\) RetryOption](<#WithJitter>)
- [func WithMaxAttempts\(n int\) RetryOption](<#WithMaxAttempts>)
- [func WithMaxBackoff\(d time.Duration\) RetryOption](<#WithMaxBackoff>)
## Variables
Sentinel errors returned via APIError.Unwrap when the description matches. Compare with errors.Is.
```go
var (
ErrUnauthorized = errors.New("telegram: unauthorized")
ErrChatNotFound = errors.New("telegram: chat not found")
ErrMessageNotModified = errors.New("telegram: message is not modified")
ErrTooManyRequests = errors.New("telegram: too many requests")
ErrBadRequest = errors.New("telegram: bad request")
ErrForbidden = errors.New("telegram: forbidden")
ErrUserNotFound = errors.New("telegram: user not found")
ErrMessageNotFound = errors.New("telegram: message not found")
)
```
Version is a fallback version string used only when Go's build info is unavailable \(replace directives, detached \`go run\`\) or has been overridden via linker flags. The authoritative version forwarded to telemetry is resolved at runtime by \[telemetry.SendForModule\] from the build info of whatever binary linked this library, so this constant does NOT need to be bumped on every release. Exposed as a var \(not const\) for ldflag override:
```
go build -ldflags="-X github.com/lukaszraczylo/go-telegram/client.Version=1.2.3"
```
```go
var Version = "0.0.0-fallback"
```
## func [Call]()
```go
func Call[Req any, Resp any](ctx context.Context, b *Bot, method string, req Req) (Resp, error)
```
Call is the single point through which every Telegram Bot API method invocation flows. It marshals the request, signs the URL with the bot token, dispatches via HTTPDoer, decodes the Result envelope, and translates non\-OK responses into typed errors.
It is generic over both request and response types. Methods with no parameters may pass a nil Req; the helper sends "\{\}" in that case so Telegram receives a syntactically valid empty object.
Call is exported because the api package \(which lives outside this one\) invokes it from generated method wrappers. User code should not normally call it directly — use the typed wrappers in package api instead.
## func [CallRaw]()
```go
func CallRaw[Req any](ctx context.Context, b *Bot, method string, req Req) (json.RawMessage, error)
```
CallRaw is like Call but returns the raw JSON of the result field instead of decoding it into a typed value. Generated method wrappers for sealed\-interface return types \(ChatMember, MenuButton, etc.\) use this helper, then dispatch through the union's UnmarshalXxx function.
CallRaw still translates non\-OK responses into \*APIError just like Call.
## func [NewDefaultHTTPDoer]()
```go
func NewDefaultHTTPDoer() *http.Client
```
NewDefaultHTTPDoer returns an \*http.Client with sensible defaults for Telegram Bot API usage:
- 60s overall timeout \(longer than typical long\-poll Timeout=30s\).
- Connection pooling sized for a small number of long\-lived hosts.
- HTTP/2 enabled \(default in net/http\).
## type [APIError]()
APIError represents a non\-OK Telegram Bot API response. It satisfies error and unwraps to a sentinel \(ErrUnauthorized, etc.\) where the description matches a known prefix, enabling errors.Is checks.
```go
type APIError struct {
Code int
Description string
Parameters *ResponseParameters
// contains filtered or unexported fields
}
```
### func \(\*APIError\) [Error]()
```go
func (e *APIError) Error() string
```
Error implements error.
### func \(\*APIError\) [IsRetryable]()
```go
func (e *APIError) IsRetryable() bool
```
IsRetryable returns true for transient HTTP statuses \(429, 5xx\).
### func \(\*APIError\) [RetryAfter]()
```go
func (e *APIError) RetryAfter() time.Duration
```
RetryAfter returns the recommended back\-off duration. It honours the Telegram\-supplied retry\_after parameter; if absent, returns 0.
### func \(\*APIError\) [Unwrap]()
```go
func (e *APIError) Unwrap() error
```
Unwrap returns the matched sentinel error, if any.
## type [BodyEncoder]()
BodyEncoder is an optional Codec extension that encodes directly into an io.Writer, skipping the intermediate \[\]byte that Marshal returns. Call uses this when present to avoid allocating the marshal result and the bytes.Reader that wraps it; codecs without it fall through to Marshal \+ bytes.NewReader.
```go
type BodyEncoder interface {
MarshalTo(w io.Writer, v any) error
}
```
## type [Bot]()
Bot is the Telegram Bot API client. Construct via New. All API methods \(declared in package api\) hang off \*Bot via thin wrappers around call.
```go
type Bot struct {
// contains filtered or unexported fields
}
```
### func [New]()
```go
func New(token string, opts ...Option) *Bot
```
New constructs a Bot with the given token and optional configuration. The default HTTP client is tuned for long\-poll workloads \(see NewDefaultHTTPDoer\); the default codec wraps encoding/json; the default logger discards records.
### func \(\*Bot\) [BaseURL]()
```go
func (b *Bot) BaseURL() string
```
BaseURL returns the configured Telegram API base URL.
### func \(\*Bot\) [Codec]()
```go
func (b *Bot) Codec() Codec
```
Codec returns the configured Codec.
### func \(\*Bot\) [HTTP]()
```go
func (b *Bot) HTTP() HTTPDoer
```
HTTP returns the underlying HTTPDoer. Exposed for adapters that need to share connection pools or for diagnostic checks.
### func \(\*Bot\) [Logger]()
```go
func (b *Bot) Logger() Logger
```
Logger returns the configured Logger.
### func \(\*Bot\) [Token]()
```go
func (b *Bot) Token() string
```
Token returns the bot token. Exposed for advanced use cases \(custom transports, manual URL building\); ordinary code does not need it.
## type [Codec]()
Codec encodes/decodes JSON payloads exchanged with the Telegram Bot API. The default implementation wraps goccy/go\-json. Users may plug in bytedance/sonic or any compatible encoder by passing WithCodec to New.
```go
type Codec interface {
Marshal(v any) ([]byte, error)
Unmarshal(data []byte, v any) error
}
```
## type [DefaultCodec]()
DefaultCodec wraps goccy/go\-json. It is the zero\-value safe default.
```go
type DefaultCodec struct{}
```
### func \(DefaultCodec\) [Marshal]()
```go
func (DefaultCodec) Marshal(v any) ([]byte, error)
```
Marshal calls json.Marshal.
### func \(DefaultCodec\) [MarshalTo]()
```go
func (DefaultCodec) MarshalTo(w io.Writer, v any) error
```
MarshalTo encodes v into w via goccy/go\-json's streaming encoder. The trailing newline that Encoder appends is valid JSON whitespace and is accepted by Telegram's parser.
### func \(DefaultCodec\) [Unmarshal]()
```go
func (DefaultCodec) Unmarshal(data []byte, v any) error
```
Unmarshal calls json.Unmarshal.
## type [FastHTTPDoer]()
FastHTTPDoer is an HTTPDoer backed by github.com/valyala/fasthttp. It trades net/http compatibility \(and HTTP/2 support\) for substantially fewer allocations per request — fasthttp pools its Request and Response objects and uses a zero\-allocation HTTP/1.1 parser.
Use it for high\-throughput bots when GC pressure matters and you don't need HTTP/2 or any net/http\-only middleware \(RoundTripper composition, the OpenTelemetry httptrace family, etc.\):
```
bot := client.New(token, client.WithHTTPClient(client.NewFastHTTPDoer()))
```
Wrap with RetryDoer the same way you would the default doer.
```go
type FastHTTPDoer struct {
// contains filtered or unexported fields
}
```
### func [NewFastHTTPDoer]()
```go
func NewFastHTTPDoer(opts ...FastHTTPDoerOption) *FastHTTPDoer
```
NewFastHTTPDoer constructs a FastHTTPDoer with sensible defaults.
### func \(\*FastHTTPDoer\) [Do]()
```go
func (d *FastHTTPDoer) Do(req *http.Request) (*http.Response, error)
```
Do satisfies HTTPDoer by translating req into a pooled fasthttp.Request, dispatching it, and returning a \*http.Response whose Body releases the pooled fasthttp.Response when Close is called.
The conversion is intentionally minimal: URL goes via req.URL.RequestURI\(\) \+ Host \(avoids re\-parsing\), header values move byte\-for\-byte, and the body is taken straight from req.Body. \*bytes.Buffer / \*bytes.Reader are recognised so we can pass the underlying bytes without io.ReadAll.
## type [FastHTTPDoerOption]()
FastHTTPDoerOption configures a FastHTTPDoer.
```go
type FastHTTPDoerOption func(*FastHTTPDoer)
```
### func [WithFastHTTPClient]()
```go
func WithFastHTTPClient(c *fasthttp.Client) FastHTTPDoerOption
```
WithFastHTTPClient swaps in a pre\-configured \*fasthttp.Client. Useful for sharing a connection pool across multiple bots or applying custom dial / TLS configuration.
### func [WithFastHTTPReadTimeout]()
```go
func WithFastHTTPReadTimeout(t time.Duration) FastHTTPDoerOption
```
WithFastHTTPReadTimeout sets the per\-request fallback timeout used when the inbound context has no deadline. Long\-poll callers should pass a value larger than the long\-poll timeout.
## type [HTTPDoer]()
HTTPDoer abstracts the HTTP transport. The default is a net/http client tuned for Telegram's long\-poll usage. Users may plug in valyala/fasthttp \(via an adapter\), or any custom retry/circuit\-breaker client by passing WithHTTPClient to New.
```go
type HTTPDoer interface {
Do(req *http.Request) (*http.Response, error)
}
```
## type [Logger]()
Logger is a slog\-shaped logging interface. Users pass any compatible implementation via WithLogger. The default is NoopLogger, which discards everything.
```go
type Logger interface {
Debug(msg string, attrs ...any)
Info(msg string, attrs ...any)
Warn(msg string, attrs ...any)
Error(msg string, attrs ...any)
}
```
## type [MultipartFile]()
MultipartFile describes a single file part in a multipart upload.
```go
type MultipartFile struct {
FieldName string
Filename string
Reader io.Reader
}
```
## type [NetworkError]()
NetworkError wraps a transport\-level failure \(DNS, TCP, TLS, timeout short of an HTTP response\).
```go
type NetworkError struct{ Err error }
```
### func \(\*NetworkError\) [Error]()
```go
func (e *NetworkError) Error() string
```
### func \(\*NetworkError\) [Unwrap]()
```go
func (e *NetworkError) Unwrap() error
```
## type [NoopLogger]()
NoopLogger discards all log records. It is the zero\-value safe default.
```go
type NoopLogger struct{}
```
### func \(NoopLogger\) [Debug]()
```go
func (NoopLogger) Debug(string, ...any)
```
### func \(NoopLogger\) [Error]()
```go
func (NoopLogger) Error(string, ...any)
```
### func \(NoopLogger\) [Info]()
```go
func (NoopLogger) Info(string, ...any)
```
### func \(NoopLogger\) [Warn]()
```go
func (NoopLogger) Warn(string, ...any)
```
## type [Option]()
Option configures a Bot at construction time. Per\-call configuration is expressed via typed parameter structs \(e.g. SendMessageParams\), not options.
```go
type Option func(*Bot)
```
### func [WithBaseURL]()
```go
func WithBaseURL(url string) Option
```
WithBaseURL overrides the API base URL. Useful for testing against a local httptest.Server, or for self\-hosted Bot API servers.
### func [WithCodec]()
```go
func WithCodec(c Codec) Option
```
WithCodec overrides the JSON codec. Pass goccy/go\-json, sonic, or any type implementing Codec to swap out encoding/json.
### func [WithHTTPClient]()
```go
func WithHTTPClient(c HTTPDoer) Option
```
WithHTTPClient overrides the HTTP transport. Pass any HTTPDoer implementation \(e.g. an \*http.Client wrapping a custom RoundTripper, or a fasthttp adapter\).
### func [WithLogger]()
```go
func WithLogger(l Logger) Option
```
WithLogger sets the logger used for diagnostic events. Passing nil silently disables logging.
## type [ParseError]()
ParseError wraps a JSON decode failure on a response body. Body is retained \(truncated to 4 KiB\); Error\(\) displays up to 256 bytes for diagnostics.
```go
type ParseError struct {
Err error
Body []byte
}
```
### func \(\*ParseError\) [Error]()
```go
func (e *ParseError) Error() string
```
### func \(\*ParseError\) [Unwrap]()
```go
func (e *ParseError) Unwrap() error
```
## type [ResponseParameters]()
ResponseParameters is the optional metadata Telegram includes on certain failures. The most common is RetryAfter \(seconds\) on 429 responses.
This type is duplicated in package api for users; keeping a copy here avoids an import cycle \(api imports client, not vice versa\).
```go
type ResponseParameters struct {
MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"`
RetryAfter int `json:"retry_after,omitempty"`
}
```
## type [Result]()
Result is the universal Telegram API response envelope. Every successful response is shaped \{"ok":true,"result":T,...\}; failure responses set ok to false and populate ErrorCode / Description / Parameters.
Result is generic over T so generated method wrappers can decode the strongly\-typed payload directly. Users do not normally construct or inspect Result values; method wrappers unwrap them and return either the typed payload or a \*APIError.
```go
type Result[T any] struct {
OK bool `json:"ok"`
Result T `json:"result,omitempty"`
ErrorCode int `json:"error_code,omitempty"`
Description string `json:"description,omitempty"`
Parameters *ResponseParameters `json:"parameters,omitempty"`
}
```
## type [RetryDoer]()
RetryDoer is an HTTPDoer that retries transient failures \(429, 5xx, and network errors\) with exponential backoff. It honours the retry\_after value Telegram supplies on rate\-limit responses.
Wrap any HTTPDoer to add retry behaviour:
```
bot := client.New(token, client.WithHTTPClient(
client.NewRetryDoer(client.NewDefaultHTTPDoer())))
```
```go
type RetryDoer struct {
// contains filtered or unexported fields
}
```
### func [NewRetryDoer]()
```go
func NewRetryDoer(inner HTTPDoer, opts ...RetryOption) *RetryDoer
```
NewRetryDoer wraps inner with retry behaviour.
### func \(\*RetryDoer\) [Do]()
```go
func (d *RetryDoer) Do(req *http.Request) (*http.Response, error)
```
Do dispatches via the inner HTTPDoer and retries on transient failures. The request body is buffered on first attempt so it can be replayed.
## type [RetryOption]()
RetryOption configures a RetryDoer.
```go
type RetryOption func(*RetryDoer)
```
### func [WithBackoffFactor]()
```go
func WithBackoffFactor(f float64) RetryOption
```
WithBackoffFactor sets the exponential growth factor. Default 2.0.
### func [WithBaseBackoff]()
```go
func WithBaseBackoff(d time.Duration) RetryOption
```
WithBaseBackoff sets the initial backoff duration. Default 500ms.
### func [WithJitter]()
```go
func WithJitter(j float64) RetryOption
```
WithJitter sets the jitter fraction \(0..1\) applied to each backoff. Default 0.2.
### func [WithMaxAttempts]()
```go
func WithMaxAttempts(n int) RetryOption
```
WithMaxAttempts sets the maximum number of attempts \(including the initial one\). Default 4 \(one initial \+ three retries\).
### func [WithMaxBackoff]()
```go
func WithMaxBackoff(d time.Duration) RetryOption
```
WithMaxBackoff caps the backoff at max. Default 30s.
Generated by [gomarkdoc]()