Go SDK
Official Go SDK for TruthMark invisible watermarking.
Installation
go get github.com/truthmark/sdkQuick Example
package main
import (
"fmt"
"log"
truthmark "github.com/truthmark/sdk"
)
func main() {
client := truthmark.NewClient(&truthmark.Config{
APIKey: "tm_live_your_key",
BaseURL: "https://truthmark-api.onrender.com",
})
// Encode
result, err := client.Encode("image.png", "Copyright 2025")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Download: %s\n", result.DownloadURL)
fmt.Printf("PSNR: %.1f dB\n", result.Metadata.PSNR)
// Decode
decoded, err := client.Decode("watermarked.png")
if err != nil {
log.Fatal(err)
}
if decoded.Found {
fmt.Printf("Message: %s\n", decoded.Message)
fmt.Printf("Confidence: %.1f%%\n", decoded.Confidence*100)
}
}API Reference
NewClient(config *Config)
Create a new client. Pass nil for defaults.
type Config struct {
APIKey string
BaseURL string
Timeout time.Duration
}Encode(imagePath, message string) (*EncodeResult, error)
Embed an invisible watermark into an image.
type EncodeResult struct {
Status string
DownloadURL string
Filename string
Metadata struct {
PSNR float64
BitsEmbedded int
}
}Decode(imagePath string) (*DecodeResult, error)
Extract watermark from an image.
type DecodeResult struct {
Found bool
Message string
Confidence float64
}Error Handling
result, err := client.Encode("image.png", "message")
if err != nil {
var apiErr *truthmark.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 401:
log.Println("Invalid API key")
case 429:
log.Printf("Rate limited. Retry after %ds", apiErr.RetryAfter)
default:
log.Printf("API error %d: %s", apiErr.StatusCode, apiErr.Message)
}
} else {
log.Printf("Network error: %v", err)
}
}Advanced Examples
HTTP Handler
func watermarkHandler(w http.ResponseWriter, r *http.Request) {
file, _, err := r.FormFile("image")
if err != nil {
http.Error(w, "Missing image", http.StatusBadRequest)
return
}
defer file.Close()
msg := r.FormValue("message")
result, err := client.Encode(file, msg)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(result)
}Concurrent Batch Processing
func batchWatermark(files []string, message string) []EncodeResult {
var wg sync.WaitGroup
results := make([]EncodeResult, len(files))
sem := make(chan struct{}, 5) // concurrency limit
for i, f := range files {
wg.Add(1)
go func(idx int, path string) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
result, err := client.Encode(path, message)
if err != nil {
log.Printf("Failed %s: %v", path, err)
return
}
results[idx] = *result
fmt.Printf("✓ %s: PSNR=%.1f dB\n", path, result.Metadata.PSNR)
}(i, f)
}
wg.Wait()
return results
}Best Practices
Use os.Getenv for API keys
Never hardcode credentials — read from environment.
Handle errors idiomatically
Use errors.As() to inspect *truthmark.APIError for status codes.
Reuse client across goroutines
The client is safe for concurrent use — create once, share everywhere.