> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pictify.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Go SDK

> Official Pictify SDK for Go

# Go SDK

The official Pictify SDK for Go provides an idiomatic Go interface for the Pictify API — generate images, PDFs, and GIFs from raw HTML, live URLs, and reusable templates.

## Installation

```bash theme={null}
go get github.com/pictify-io/pictify-go
```

## Quick Start

```go theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/pictify-io/pictify-go"
)

func main() {
    client := pictify.NewClient("your-api-key")

    // Render raw HTML to a PNG.
    img, err := client.RenderHTML(context.Background(), &pictify.RenderHTMLOptions{
        HTML:   `<div style="font-size:48px;padding:40px">Hello World</div>`,
        Width:  1200,
        Height: 630,
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(img.URL)
}
```

## API

The SDK talks to the Pictify API at `https://api.pictify.io`. Every call sends `Authorization: Bearer <api-key>`.

| Method | Endpoint | Returns |
| - | - | - |
| `RenderHTML` | `POST /image` | `*ImageResult` `{URL, ID, CreatedAt}` |
| `RenderURL` | `POST /image` | `*ImageResult` |
| `Render` | `POST /templates/{uid}/render` | `*RenderResult` (results\[] envelope) |
| `RenderLayouts` | `POST /templates/{uid}/render` | `*RenderResult` |
| `RenderGIF` | `POST /gif` | `*GIFResult` (flattened) |
| `RenderBatch` | `POST /templates/{uid}/batch-render` | `*BatchJob` (async, HTTP 202) |
| `GetBatchResults` | `GET /templates/batch/{id}/results` | `*BatchResults` |
| `GetTemplate` | `GET /templates/{uid}` | `*Template` (unwrapped) |
| `ListTemplates` | `GET /templates` | `*TemplateList` `{Templates, Pagination}` |
| `CreateTemplate` | `POST /templates` | `*Template` (unwrapped) |

## Configuration

`NewClient` takes the API key plus functional options.

```go theme={null}
client := pictify.NewClient(
    "your-api-key",
    pictify.WithBaseURL("https://api.pictify.io"), // default
    pictify.WithTimeout(30*time.Second),
    pictify.WithMaxRetries(3),
    pictify.WithHTTPClient(&http.Client{
        Transport: &http.Transport{
            MaxIdleConns:    10,
            IdleConnTimeout: 30 * time.Second,
        },
    }),
)
```

<Warning>
  Keep your API key secret. Read it from an environment variable (e.g. `os.Getenv("PICTIFY_API_KEY")`) and never expose it in client-side code or public repositories.
</Warning>

## Render an Image from HTML

`POST /image` — returns `{URL, ID, CreatedAt}`.

```go theme={null}
img, err := client.RenderHTML(ctx, &pictify.RenderHTMLOptions{
    HTML:     `<div class="card">Hello</div>`,
    CSS:      ".card { padding: 40px; color: #0ea5e9; }", // injected as <style> before the HTML
    Width:    1200,                                       // default 1280
    Height:   630,                                        // default 720
    Selector: ".card",                                    // optional: crop to an element
    Format:   pictify.FormatPNG,                          // png (default), jpg, jpeg, webp, pdf
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(img.URL)
```

The `/image` endpoint accepts a single `html` field, so any `CSS` you pass is injected into a `<style>` tag prepended to the HTML. `Format` maps to the endpoint's `fileExtension`.

## Screenshot a Live URL

`POST /image` with a `url`.

```go theme={null}
img, err := client.RenderURL(ctx, &pictify.RenderURLOptions{
    URL:    "https://example.com",
    Width:  1280,
    Height: 720,
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(img.URL)
```

## Render a Template

`POST /templates/{uid}/render` — returns a `results[]` envelope. Use `result.URL()` for the first result's URL.

```go theme={null}
result, err := client.Render(ctx, &pictify.RenderOptions{
    TemplateID: "XL13XACH2V",
    Variables:  map[string]interface{}{"name": "Ada", "company": "Pictify"},
    Format:     pictify.FormatPNG, // template renders also support pdf
    Quality:    0.9,               // 0.1–1.0 for raster output
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.URL())          // results[0].url
for _, item := range result.Results {
    fmt.Printf("%s: %s (%dx%d)\n", item.Layout, item.URL, item.Width, item.Height)
}
```

### Layout Variants

Templates can have multiple layout variants (e.g. landscape, square, story) created via AI Resize in the Pictify editor. Render several at once with `RenderLayouts` (max 20). Use `"default"` for the base layout. Layouts that can't be rendered are returned in `result.Errors` rather than failing the whole call.

```go theme={null}
result, err := client.RenderLayouts(ctx, &pictify.RenderOptions{
    TemplateID: "XL13XACH2V",
    Variables:  map[string]interface{}{"name": "Ada", "company": "Pictify"},
}, []string{"default", "twitter-post", "instagram-story"})
if err != nil {
    log.Fatal(err)
}
for _, item := range result.Results {
    fmt.Printf("%s: %s\n", item.Layout, item.URL)
}
for _, e := range result.Errors {
    fmt.Printf("layout %s failed: %s\n", e.Layout, e.Error)
}
```

## Render an Animated GIF

`POST /gif` — provide exactly one source (`HTML`, `URL`, or `TemplateID`). The API's nested `{gif: {...}}` envelope is flattened into `*GIFResult`.

```go theme={null}
gif, err := client.RenderGIF(ctx, &pictify.GIFOptions{
    HTML: `<style>@keyframes p{0%{opacity:.2}50%{opacity:1}100%{opacity:.2}}` +
        `div{font-size:40px;padding:30px;animation:p 2s infinite}</style>` +
        `<div>Hi</div>`,
    Width:   400,                     // default 800
    Height:  200,                     // default 600
    Quality: pictify.GIFQualityLow,   // low | medium (default) | high
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(gif.URL, gif.UID, gif.AnimationLength)
```

To render a GIF from a template, set `TemplateID` (and optionally `Variables`). The source must be animated; a static source returns a render error (HTTP 422).

## Batch Rendering (async)

`POST /templates/{uid}/batch-render` returns immediately (HTTP 202) with a `BatchID`. The job runs asynchronously — poll `GetBatchResults` to track progress.

```go theme={null}
job, err := client.RenderBatch(ctx, &pictify.BatchOptions{
    TemplateID: "XL13XACH2V",
    VariableSets: []map[string]interface{}{
        {"name": "Ada", "company": "Pictify"},
        {"name": "Grace", "company": "Pictify"},
    },
    Format:      pictify.FormatPNG,
    Concurrency: 5, // 1–10, default 5
})
if err != nil {
    log.Fatal(err)
}
fmt.Printf("batch %s: %s (%d items)\n", job.BatchID, job.Status, job.TotalItems)

results, err := client.GetBatchResults(ctx, job.BatchID)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("status=%s completed=%d/%d failed=%d\n",
    results.Status, results.CompletedItems, results.TotalItems, results.FailedItems)
```

<Warning>
  Rendered URLs are **not** returned by the poll endpoint; they are delivered via the `render.completed` webhook. The poll response reports each item's `Index`, `Success`, and variable names (plus an `Error` on failures).
</Warning>

## Template Management

```go theme={null}
// Create a template from HTML. Variables are auto-discovered from {{name}} tokens.
tmpl, err := client.CreateTemplate(ctx, &pictify.CreateTemplateOptions{
    HTML:   `<div style="padding:20px">Hi {{firstName}}</div>`,
    Name:   "Welcome Card",
    Width:  600,
    Height: 200,
})
if err != nil {
    log.Fatal(err)
}
fmt.Println(tmpl.UID)
for _, v := range tmpl.VariableDefinitions {
    fmt.Printf("  - %s (%s)\n", v.Name, v.Type)
}

// Fetch a single template by UID.
tmpl, err = client.GetTemplate(ctx, "XL13XACH2V")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s: %s (%dx%d)\n", tmpl.UID, tmpl.Name, tmpl.Width, tmpl.Height)

// List templates with pagination.
list, err := client.ListTemplates(ctx, &pictify.ListTemplatesOptions{
    Page:  1,
    Limit: 20,           // max 100, default 12
    Sort:  "newest",     // newest | oldest | name
})
if err != nil {
    log.Fatal(err)
}
for _, t := range list.Templates {
    fmt.Printf("%s: %s\n", t.UID, t.Name)
}
fmt.Printf("page %d of %d (%d total)\n",
    list.Pagination.Page, list.Pagination.TotalPages, list.Pagination.Total)
```

`Template` keys by `UID` (not `id`) and declares variables in `VariableDefinitions`. Any unknown engine-specific fields are preserved in `Template.Extra` (a `map[string]json.RawMessage`).

## Error Handling

HTTP errors are mapped to typed errors. Each one embeds `*PictifyError`, so you can match either the concrete type or the base with `errors.As`. The error message resolves as `body.error` → `body.message` → HTTP status text.

| Status | Error type |
| - | - |
| 401 | `*AuthenticationError` |
| 402 | `*QuotaExceededError` |
| 404 | `*TemplateNotFoundError` |
| 422 / other 4xx | `*RenderError` (422 carries field-level `Errors`) |
| 429 | `*QuotaExceededError` (when `code == "quota_exceeded"`) or `*RateLimitError` |
| 5xx | `*ServerError` |
| transport failure | `*NetworkError` |
| timeout / context deadline | `*TimeoutError` |

```go theme={null}
import (
    "errors"

    "github.com/pictify-io/pictify-go"
)

result, err := client.Render(ctx, opts)
if err != nil {
    var authErr *pictify.AuthenticationError
    var notFoundErr *pictify.TemplateNotFoundError
    var rateLimitErr *pictify.RateLimitError
    var quotaErr *pictify.QuotaExceededError
    var renderErr *pictify.RenderError
    var serverErr *pictify.ServerError
    var networkErr *pictify.NetworkError

    switch {
    case errors.As(err, &authErr):
        log.Println("invalid API key")
    case errors.As(err, &notFoundErr):
        log.Println("template not found")
    case errors.As(err, &rateLimitErr):
        log.Printf("rate limited; retry after %ds", rateLimitErr.RetryAfter)
    case errors.As(err, &quotaErr):
        log.Println("render quota exceeded")
    case errors.As(err, &renderErr):
        log.Printf("render failed: %s (%v)", renderErr.Message, renderErr.Errors)
    case errors.As(err, &serverErr):
        log.Printf("server error: %s", serverErr.Message)
    case errors.As(err, &networkErr):
        log.Printf("network error: %v", networkErr.Err)
    default:
        log.Printf("error: %v", err)
    }
}
```

Only 5xx and network failures are retried (with exponential backoff); 4xx responses are never retried.

## Context Support

All methods take a `context.Context` for cancellation and timeouts:

```go theme={null}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

img, err := client.RenderHTML(ctx, &pictify.RenderHTMLOptions{
    HTML:   "<h1>Hello</h1>",
    Width:  1200,
    Height: 630,
})
```

## Concurrent Requests

The client is safe for concurrent use:

```go theme={null}
var wg sync.WaitGroup
results := make(chan *pictify.ImageResult, 10)

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        img, err := client.RenderHTML(ctx, &pictify.RenderHTMLOptions{
            HTML:   fmt.Sprintf("<h1>Image %d</h1>", i),
            Width:  1200,
            Height: 630,
        })
        if err == nil {
            results <- img
        }
    }(i)
}

wg.Wait()
close(results)

for img := range results {
    fmt.Println(img.URL)
}
```

## Video Templates

Render MP4 video — or animated GIF — from video templates, generate new templates with AI, or upload a Remotion scene you wrote. Video calls use a longer per-call timeout internally (render 5m, authoring 3m); context deadlines still cancel earlier.

```go theme={null}
videos, _ := client.ListVideoTemplates(ctx)

video, err := client.RenderVideo(ctx, &pictify.RenderVideoOptions{
    TemplateID: videos[0].UID,
    Variables:  map[string]any{"title": "Welcome, Maya!"},
    Format:     pictify.VideoFormatGIF, // or VideoFormatMP4 (default)
})
fmt.Println(video.URL)

generated, err := client.GenerateVideoTemplate(ctx, &pictify.GenerateVideoTemplateOptions{
    Prompt: "An 8 second product launch teaser — dark, electric, type-driven",
})

// The compile gate runs BEFORE saving: invalid tsx returns a *RenderError
// with the compiler errors in .Errors, and nothing is created.
template, err := client.CreateVideoTemplate(ctx, &pictify.CreateVideoTemplateOptions{
    Name: "My scene", TSX: sceneSource, DurationSeconds: 8,
})
```

## API Reference

See the [API Reference](/api-reference/overview) for full endpoint documentation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.