Go SDK
The official Pictify SDK for Go provides an idiomatic Go interface for the Pictify API.Installation
go get github.com/pictify/pictify-go
Quick Start
package main
import (
"fmt"
"log"
"github.com/pictify/pictify-go"
)
func main() {
client := pictify.NewClient("pk_live_your_api_key")
image, err := client.Images.Create(&pictify.ImageCreateParams{
HTML: "<h1 style=\"color: #667eea;\">Hello World</h1>",
Width: 1200,
Height: 630,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(image.URL)
}
Configuration
Basic Configuration
client := pictify.NewClient("pk_live_your_api_key")
Advanced Configuration
client := pictify.NewClient(
"pk_live_your_api_key",
pictify.WithBaseURL("https://api.pictify.io/v1"),
pictify.WithTimeout(30 * time.Second),
pictify.WithRetries(3),
)
Environment Variables
import "os"
client := pictify.NewClient(os.Getenv("PICTIFY_API_KEY"))
Images
Generate from HTML
image, err := client.Images.Create(&pictify.ImageCreateParams{
HTML: `
<div style="width: 1200px; height: 630px; background: #667eea;
display: flex; align-items: center; justify-content: center;">
<h1 style="color: white; font-size: 48px;">Hello World</h1>
</div>
`,
Width: 1200,
Height: 630,
Format: pictify.FormatPNG,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(image.URL) // https://cdn.pictify.io/renders/...
fmt.Println(image.ID) // img_abc123
fmt.Println(image.Width) // 1200
fmt.Println(image.Height) // 630
Generate from URL
image, err := client.Images.Create(&pictify.ImageCreateParams{
URL: "https://example.com",
Width: 1200,
Height: 630,
FullPage: false,
})
Canvas Rendering
image, err := client.Images.Canvas(&pictify.CanvasParams{
FabricJSData: map[string]interface{}{
"version": "5.3.0",
"objects": []map[string]interface{}{
{"type": "rect", "fill": "#667eea", "width": 1200, "height": 630},
{"type": "textbox", "text": "{{title}}", "fill": "white", "fontSize": 48},
},
},
Variables: map[string]interface{}{
"title": "Dynamic Content",
},
Width: 1200,
Height: 630,
})
Agent Screenshot
image, err := client.Images.AgentScreenshot(&pictify.AgentScreenshotParams{
Prompt: "Take a screenshot of the pricing section on stripe.com",
})
GIFs
Create from HTML
gif, err := client.GIFs.Create(&pictify.GIFCreateParams{
HTML: `
<div class="container">
<style>
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.pulse { animation: pulse 1s infinite; }
</style>
<div class="pulse">Animated!</div>
</div>
`,
Width: 400,
Height: 400,
})
Capture from URL
gif, err := client.GIFs.Capture(&pictify.GIFCaptureParams{
URL: "https://example.com/animated",
Width: 800,
Height: 600,
Quality: pictify.QualityHigh,
FrameDurationSeconds: 5,
})
PDFs
Single Page
pdf, err := client.PDFs.Render(&pictify.PDFRenderParams{
TemplateUID: "tmpl_invoice",
Variables: map[string]interface{}{
"invoiceNumber": "INV-001",
"items": []map[string]interface{}{
{"name": "Service", "price": 99.00},
},
"total": 99.00,
},
Options: &pictify.PDFOptions{
Preset: pictify.PresetA4,
Margins: &pictify.Margins{
Top: 40, Bottom: 40, Left: 30, Right: 30,
},
},
})
Multi-Page
pdf, err := client.PDFs.MultiPage(&pictify.PDFMultiPageParams{
TemplateUID: "tmpl_report",
VariableSets: []map[string]interface{}{
{"pageTitle": "Introduction", "content": "..."},
{"pageTitle": "Analysis", "content": "..."},
{"pageTitle": "Conclusion", "content": "..."},
},
Options: &pictify.PDFOptions{
Preset: pictify.PresetA4,
},
})
Templates
List Templates
result, err := client.Templates.List(&pictify.ListParams{
Page: 1,
Limit: 20,
})
for _, tmpl := range result.Templates {
fmt.Printf("%s: %s\n", tmpl.UID, tmpl.Name)
}
Create Template
template, err := client.Templates.Create(&pictify.TemplateCreateParams{
Name: "Social Card",
HTML: "<h1>{{title}}</h1><p>{{description}}</p>",
Width: 1200,
Height: 630,
})
Render Template
image, err := client.Templates.Render("tmpl_abc123", &pictify.RenderParams{
Variables: map[string]interface{}{
"title": "My Post",
"description": "An interesting article",
},
Format: pictify.FormatPNG,
})
Batch Render
batch, err := client.Templates.BatchRender("tmpl_abc123", &pictify.BatchRenderParams{
VariableSets: []map[string]interface{}{
{"title": "Post 1"},
{"title": "Post 2"},
{"title": "Post 3"},
},
WebhookURL: "https://your-server.com/webhooks/batch",
})
// Later, get results
results, err := client.Templates.GetBatchResults(batch.ID, nil)
Webhooks
Create Subscription
subscription, err := client.Webhooks.Create(&pictify.WebhookCreateParams{
Event: pictify.EventRenderCompleted,
TargetURL: "https://your-server.com/webhooks/pictify",
})
// Store this secret securely!
fmt.Println(subscription.Secret)
Verify Signature
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"math"
"strconv"
"strings"
"time"
)
func VerifyWebhookSignature(payload, signatureHeader, secret string) error {
parts := make(map[string]string)
for _, pair := range strings.Split(signatureHeader, ",") {
kv := strings.SplitN(pair, "=", 2)
if len(kv) == 2 {
parts[kv[0]] = kv[1]
}
}
timestamp, _ := strconv.ParseInt(parts["t"], 10, 64)
providedSignature := parts["v1"]
// Reject if timestamp is older than 5 minutes
if math.Abs(float64(time.Now().Unix()-timestamp)) > 300 {
return fmt.Errorf("webhook timestamp too old")
}
signedPayload := fmt.Sprintf("%d.%s", timestamp, payload)
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(signedPayload))
expectedSignature := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(providedSignature), []byte(expectedSignature)) {
return fmt.Errorf("invalid signature")
}
return nil
}
HTTP Handler
package main
import (
"encoding/json"
"io"
"net/http"
)
func webhookHandler(w http.ResponseWriter, r *http.Request) {
signature := r.Header.Get("X-Pictify-Signature")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read body", http.StatusBadRequest)
return
}
if err := VerifyWebhookSignature(string(body), signature, webhookSecret); err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
var event pictify.WebhookEvent
if err := json.Unmarshal(body, &event); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
fmt.Printf("Received event: %s\n", event.Event)
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
Bindings
Create Binding
binding, err := client.Bindings.Create(&pictify.BindingCreateParams{
Name: "GitHub Stats",
TemplateUID: "tmpl_github",
DataURL: "https://api.github.com/repos/your/repo",
DataMapping: map[string]string{
"stars": "stargazers_count",
"forks": "forks_count",
},
Schedule: "0 * * * *", // Hourly
})
// Permanent image URL that auto-updates
fmt.Println(binding.ImageURL)
Trigger Refresh
err := client.Bindings.Refresh("bind_abc123")
Error Handling
image, err := client.Images.Create(&pictify.ImageCreateParams{...})
if err != nil {
switch e := err.(type) {
case *pictify.RateLimitError:
// Wait and retry
fmt.Printf("Rate limited. Retry after %d seconds\n", e.RetryAfter)
time.Sleep(time.Duration(e.RetryAfter) * time.Second)
case *pictify.ValidationError:
// Fix validation issues
fmt.Printf("Validation errors: %v\n", e.Errors)
case *pictify.AuthenticationError:
// Check API key
fmt.Println("Invalid API key")
case *pictify.APIError:
// General API error
fmt.Printf("API Error: %s (status: %d)\n", e.Message, e.Status)
default:
// Network or other error
log.Fatal(err)
}
}
Context Support
All methods support context for cancellation and timeouts:ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
image, err := client.Images.CreateWithContext(ctx, &pictify.ImageCreateParams{
HTML: "<h1>Hello</h1>",
Width: 1200,
Height: 630,
})
Concurrent Requests
The client is safe for concurrent use:var wg sync.WaitGroup
results := make(chan *pictify.Image, 10)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
image, err := client.Images.Create(&pictify.ImageCreateParams{
HTML: fmt.Sprintf("<h1>Image %d</h1>", i),
Width: 1200,
Height: 630,
})
if err == nil {
results <- image
}
}(i)
}
wg.Wait()
close(results)
for img := range results {
fmt.Println(img.URL)
}