---
title: "Linkbreakers Go SDK: Complete Integration Guide"
description: "Learn how to integrate the Linkbreakers Go SDK in your backend application for programmatic link management, visitor tracking, QR code generation, and analytics. Includes installation, authentication, and real code examples for various Go frameworks."
canonical: "https://linkbreakers.com/help/article/golang-sdk-quickstart"
last-updated: 2026-10-11
---

# Linkbreakers Go SDK: Complete Integration Guide

> Learn how to integrate the Linkbreakers Go SDK in your backend application for programmatic link management, visitor tracking, QR code generation, and analytics. Includes installation, authentication, and real code examples for various Go frameworks.

## Short answer

The Linkbreakers Go SDK enables programmatic link management, visitor identification, QR code generation, and analytics access from your Go backend applications. Install it with `go get github.com/linkbreakers-com/linkbreakers-go`, authenticate with a secret API key, and start creating trackable links for your campaigns, products, or events.

## Installation

Install the SDK using Go modules:

```bash
go get github.com/linkbreakers-com/linkbreakers-go
```

The SDK will be automatically added to your `go.mod` file:

```go
require github.com/linkbreakers-com/linkbreakers-go v1.183.0
```

## Understanding API keys for Go

The Go SDK is designed for **backend/server-side use only** and requires a **secret API key** with full workspace access.

### Secret keys

**Backend-only.** These JWT tokens grant full API access and must never be exposed in public repositories or client-side code.

**What they allow:**
- Create, update, and delete links
- Generate and customize QR codes
- Identify and track visitors
- Access analytics and metrics
- Manage workspace resources
- Full API access

**Where to use:**
- Web servers (Gin, Echo, Fiber)
- gRPC services
- Background workers and cron jobs
- Microservices
- CLI tools
- API gateways

**Security note:** Go applications typically run on servers, making them perfect for secret key usage. Never log keys, commit them to git, or expose them in error messages.

## Creating a secret API key

Create your API key from the dashboard:

1. Log in to [app.linkbreakers.com](https://app.linkbreakers.com)
2. Navigate to **Dashboard → API Tokens**
3. Click **Create API Token**
4. Select **Secret Key** (full API access)
5. Give it a descriptive name (e.g., "Production Backend" or "Go Service")
6. Copy the generated JWT token immediately

**Important:** You won't see the key again after creation. Store it in environment variables or a secret management system.

## Quick start

Initialize the client and create your first shortened link:

```go
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func main() {
    // Configure API client with your secret key
    config := linkbreakers.NewConfiguration()
    config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("LINKBREAKERS_SECRET_KEY")))
    config.Servers = linkbreakers.ServerConfigurations{
        {URL: "https://api.linkbreakers.com"},
    }

    client := linkbreakers.NewAPIClient(config)
    ctx := context.Background()

    // Create a shortened link
    createReq := linkbreakers.NewCreateLinkRequest("https://example.com/product")
    createReq.SetName("Product Launch - Spring 2025")
    createReq.SetTags([]string{"marketing", "product-launch"})

    response, _, err := client.LinksAPI.LinksServiceCreate(ctx).CreateLinkRequest(*createReq).Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Short URL: %s\n", response.Link.GetShortlink())
    fmt.Printf("Link ID: %s\n", response.Link.GetId())
    fmt.Printf("QR Code: %s\n", response.Link.GetQrcodeSignedUrl())
}
```

## Environment variables (best practice)

Never hardcode API keys. Use environment variables:

```go
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func getClient() *linkbreakers.APIClient {
    config := linkbreakers.NewConfiguration()
    config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("LINKBREAKERS_SECRET_KEY")))
    config.Servers = linkbreakers.ServerConfigurations{
        {URL: "https://api.linkbreakers.com"},
    }
    return linkbreakers.NewAPIClient(config)
}

func main() {
    client := getClient()
    ctx := context.Background()

    // Use the client for API operations
    // ...
}
```

**Set your environment variable:**

```bash
# .env file (use godotenv to load)
export LINKBREAKERS_SECRET_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3Jrc3BhY2VfaWQiOiIxMjM0IiwidHlwZSI6InNlY3JldCJ9...
```

**Loading .env files with godotenv:**

```go
package main

import (
    "log"

    "github.com/joho/godotenv"
)

func init() {
    // Load .env file
    if err := godotenv.Load(); err != nil {
        log.Println("No .env file found")
    }
}
```

## Creating and managing links

### Basic link creation

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func createBasicLink(client *linkbreakers.APIClient) {
    ctx := context.Background()

    createReq := linkbreakers.NewCreateLinkRequest("https://example.com/summer-sale")
    createReq.SetName("Summer Sale 2025")
    createReq.SetTags([]string{"campaign", "summer", "email"})

    response, _, err := client.LinksAPI.LinksServiceCreate(ctx).CreateLinkRequest(*createReq).Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created: %s\n", response.Link.GetShortlink())
}
```

### Advanced link options

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func createAdvancedLinks(client *linkbreakers.APIClient) {
    ctx := context.Background()

    // Create link with custom shortlink
    customReq := linkbreakers.NewCreateLinkRequest("https://example.com/docs")
    customReq.SetShortlink("docs") // Creates lbr.ai/docs
    customReq.SetName("Documentation Portal")
    customReq.SetFallbackDestination("https://example.com/404")
    customReq.SetTags([]string{"internal", "docs"})

    customLink, _, err := client.LinksAPI.LinksServiceCreate(ctx).CreateLinkRequest(*customReq).Execute()
    if err != nil {
        log.Fatal(err)
    }

    // Create link with metadata for tracking
    trackedReq := linkbreakers.NewCreateLinkRequest("https://example.com/product/123")
    trackedReq.SetName("Product 123 - Email Campaign")
    trackedReq.SetMetadata(map[string]string{
        "product_id":   "123",
        "campaign_id":  "spring-2025",
        "utm_source":   "email",
        "utm_medium":   "newsletter",
        "utm_campaign": "product-launch",
    })
    trackedReq.SetTags([]string{"product", "email"})

    trackedLink, _, err := client.LinksAPI.LinksServiceCreate(ctx).CreateLinkRequest(*trackedReq).Execute()
    if err != nil {
        log.Fatal(err)
    }

    // Create link with QR code (wait for generation)
    qrReq := linkbreakers.NewCreateLinkRequest("https://example.com/event-registration")
    qrReq.SetName("Conference 2025 Registration")
    qrReq.SetWaitForQrcode(true) // Blocks until QR is generated
    qrReq.SetTags([]string{"event", "conference", "qr-code"})

    qrLink, _, err := client.LinksAPI.LinksServiceCreate(ctx).CreateLinkRequest(*qrReq).Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Download QR code: %s\n", qrLink.Link.GetQrcodeSignedUrl())
}
```

### Listing and filtering links

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func listLinks(client *linkbreakers.APIClient) {
    ctx := context.Background()

    // List links with filtering
    pageSize := int32(50)
    sortBy := linkbreakers.LINKBREAKERSV1LINKSSORTFIELD_UPDATED_AT
    sortDirection := linkbreakers.LINKBREAKERSV1SORTDIRECTION_DESC

    response, _, err := client.LinksAPI.LinksServiceList(ctx).
        PageSize(pageSize).
        Tags([]string{"marketing", "email"}).
        Search("campaign").
        SortBy(sortBy).
        SortDirection(sortDirection).
        Execute()

    if err != nil {
        log.Fatal(err)
    }

    for _, link := range response.GetLinks() {
        fmt.Printf("%s: %s\n", link.GetName(), link.GetShortlink())
        fmt.Printf("  Tags: %v\n", link.GetTags())
        fmt.Printf("  Created: %s\n", link.GetCreatedAt())
    }
}
```

### Updating and deleting links

```go
package main

import (
    "context"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func updateAndDeleteLink(client *linkbreakers.APIClient, linkID string) {
    ctx := context.Background()

    // Get a specific link
    linkResp, _, err := client.LinksAPI.LinksServiceGet(ctx, linkID).
        Include([]string{"tags", "qrcodeSignedUrl"}).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    // Update link
    updateReq := linkbreakers.NewUpdateLinkRequest()
    updateReq.SetName("Updated Campaign Name")
    updateReq.SetTags([]string{"marketing", "q2-2025", "updated"})

    _, _, err = client.LinksAPI.LinksServiceUpdate(ctx, linkResp.Link.GetId()).
        UpdateLinkRequest(*updateReq).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    // Delete link
    _, err = client.LinksAPI.LinksServiceDelete(ctx, linkResp.Link.GetId()).Execute()
    if err != nil {
        log.Fatal(err)
    }
}
```

## Bulk link creation

Create hundreds of links efficiently in a single API call:

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

type Product struct {
    ID   string
    Name string
    URL  string
}

func createBulkLinks(client *linkbreakers.APIClient) {
    ctx := context.Background()

    // Prepare bulk links (e.g., from a product catalog)
    products := []Product{
        {ID: "001", Name: "Widget A", URL: "https://example.com/products/001"},
        {ID: "002", Name: "Widget B", URL: "https://example.com/products/002"},
        {ID: "003", Name: "Widget C", URL: "https://example.com/products/003"},
    }

    var linksToCreate []linkbreakers.CreateLinkRequest
    for _, p := range products {
        req := linkbreakers.NewCreateLinkRequest(p.URL)
        req.SetName(fmt.Sprintf("Product: %s", p.Name))
        req.SetTags([]string{"product", "catalog"})
        req.SetMetadata(map[string]string{
            "product_id": p.ID,
            "sku":        fmt.Sprintf("SKU-%s", p.ID),
        })
        linksToCreate = append(linksToCreate, *req)
    }

    // Create all links in one request
    bulkReq := linkbreakers.NewCreateBulkLinksRequest(linksToCreate)
    response, _, err := client.LinksAPI.LinksServiceCreateBulk(ctx).
        CreateBulkLinksRequest(*bulkReq).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created %d links\n", len(response.GetLinks()))
    for _, link := range response.GetLinks() {
        fmt.Printf("  %s: %s\n", link.GetName(), link.GetShortlink())
    }
}
```

**When to use bulk creation:**
- Importing product catalogs
- Generating links from database records
- Campaign setup with many URLs
- Automated link generation pipelines

## Visitor identification and tracking

Track and identify visitors using their LBID (Linkbreakers ID) from click/scan events:

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func identifyVisitor(client *linkbreakers.APIClient, lbid string) {
    ctx := context.Background()

    // Prepare visitor data
    visitorData := map[string]interface{}{
        // System fields (prefixed with "$")
        "$email":     "john.doe@example.com",
        "$phone":     "+14155551234",
        "$firstName": "John",
        "$lastName":  "Doe",

        // Custom attributes (no "$" prefix)
        "company":    "Acme Corporation",
        "jobTitle":   "Product Manager",
        "plan":       "enterprise",
        "signupDate": "2024-01-15",
        "industry":   "SaaS",
        "employees":  250,
    }

    visitorInput := linkbreakers.NewVisitorInput()
    visitorInput.SetData(visitorData)

    identifyReq := linkbreakers.NewIdentifyRequest(lbid, *visitorInput)
    identifyReq.SetSetOnce(false) // True = only update empty fields

    response, _, err := client.VisitorsAPI.VisitorsServiceIdentify(ctx).
        IdentifyRequest(*identifyReq).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("New profile created: %v\n", response.GetCreated())
    fmt.Printf("Visitor ID: %s\n", response.Visitor.GetId())
    fmt.Printf("Email: %s\n", response.Visitor.GetEmail())
}
```

**Understanding LBID:**

When visitors click your Linkbreakers links with **conversion tracking enabled**, a `?lbid=...` parameter is added to the destination URL. This LBID connects the visitor to the specific link click, enabling attribution and analytics.

Extract LBID from incoming requests and pass it to the identification API to build visitor profiles. Learn more in our [What is LBID?](/help/article/what-is-the-linkbreakers-id-lbid) guide.

### Working with visitor data

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func workWithVisitors(client *linkbreakers.APIClient, visitorID string) {
    ctx := context.Background()

    // Get visitor details
    visitor, _, err := client.VisitorsAPI.VisitorsServiceGet(ctx, visitorID).
        Include([]string{"devices", "events", "links"}).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Visitor: %s\n", visitor.GetEmail())
    fmt.Printf("Devices: %d\n", len(visitor.GetDevices()))
    fmt.Printf("Events: %d\n", len(visitor.GetEvents()))

    // List visitors with filtering
    pageSize := int32(100)
    visitorsList, _, err := client.VisitorsAPI.VisitorsServiceList(ctx).
        PageSize(pageSize).
        Email("user@example.com").
        LinkId("link-uuid").
        Search("Acme Corp").
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    // Update visitor attributes
    updateData := map[string]interface{}{
        "$email":       "updated@example.com",
        "plan":         "enterprise",
        "lastActivity": "2025-03-31",
    }

    visitorUpdate := linkbreakers.NewVisitorInput()
    visitorUpdate.SetData(updateData)

    updateReq := linkbreakers.NewVisitorsServiceUpdateBody(*visitorUpdate)

    _, _, err = client.VisitorsAPI.VisitorsServiceUpdate(ctx, visitorID).
        VisitorsServiceUpdateBody(*updateReq).
        Execute()
    if err != nil {
        log.Fatal(err)
    }
}
```

## Accessing analytics and metrics

Retrieve event data and workspace metrics:

```go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func getAnalytics(client *linkbreakers.APIClient, linkID string) {
    ctx := context.Background()

    // Get events for a specific link (last 30 days)
    endDate := time.Now()
    startDate := endDate.AddDate(0, 0, -30)

    eventsResp, _, err := client.EventsAPI.EventsServiceList(ctx).
        LinkId(linkID).
        StartDate(startDate).
        EndDate(endDate).
        PageSize(1000).
        Include([]string{"visitor", "device", "link"}).
        Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Total events: %d\n", len(eventsResp.GetEvents()))
    for i, event := range eventsResp.GetEvents() {
        if i >= 10 {
            break
        }
        fmt.Printf("  %s - %s\n", event.GetAction(), event.GetCreatedAt())
    }

    // Get workspace metrics
    metrics, _, err := client.MetricsAPI.MetricsServiceGetWorkspaceMetrics(ctx).Execute()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("\nWorkspace Stats:")
    fmt.Printf("  Total links: %d\n", metrics.GetTotalLinks())
    fmt.Printf("  Total clicks: %d\n", metrics.GetTotalClicks())
    fmt.Printf("  Total visitors: %d\n", metrics.GetTotalVisitors())
}
```

## Framework integration

### Gin

```go
package main

import (
    "context"
    "fmt"
    "net/http"
    "os"

    "github.com/gin-gonic/gin"
    "github.com/linkbreakers-com/linkbreakers-go"
)

func getClient() *linkbreakers.APIClient {
    config := linkbreakers.NewConfiguration()
    config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("LINKBREAKERS_SECRET_KEY")))
    config.Servers = linkbreakers.ServerConfigurations{
        {URL: "https://api.linkbreakers.com"},
    }
    return linkbreakers.NewAPIClient(config)
}

func main() {
    r := gin.Default()
    client := getClient()

    r.POST("/api/create-link", func(c *gin.Context) {
        var req struct {
            Destination string   `json:"destination" binding:"required"`
            Name        string   `json:"name"`
            Tags        []string `json:"tags"`
        }

        if err := c.ShouldBindJSON(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        createReq := linkbreakers.NewCreateLinkRequest(req.Destination)
        if req.Name != "" {
            createReq.SetName(req.Name)
        }
        if len(req.Tags) > 0 {
            createReq.SetTags(req.Tags)
        }

        response, _, err := client.LinksAPI.LinksServiceCreate(context.Background()).
            CreateLinkRequest(*createReq).
            Execute()

        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, gin.H{
            "success":   true,
            "shortlink": response.Link.GetShortlink(),
            "qr_code":   response.Link.GetQrcodeSignedUrl(),
        })
    })

    r.GET("/api/links", func(c *gin.Context) {
        tags := c.QueryArray("tags")
        pageSize := int32(50)

        response, _, err := client.LinksAPI.LinksServiceList(context.Background()).
            PageSize(pageSize).
            Tags(tags).
            Execute()

        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }

        var links []gin.H
        for _, link := range response.GetLinks() {
            links = append(links, gin.H{
                "id":          link.GetId(),
                "name":        link.GetName(),
                "shortlink":   link.GetShortlink(),
                "destination": link.GetDestination(),
            })
        }

        c.JSON(http.StatusOK, gin.H{"links": links})
    })

    r.Run(":8080")
}
```

### Echo

```go
package main

import (
    "context"
    "fmt"
    "net/http"
    "os"

    "github.com/labstack/echo/v4"
    "github.com/linkbreakers-com/linkbreakers-go"
)

func getClient() *linkbreakers.APIClient {
    config := linkbreakers.NewConfiguration()
    config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("LINKBREAKERS_SECRET_KEY")))
    config.Servers = linkbreakers.ServerConfigurations{
        {URL: "https://api.linkbreakers.com"},
    }
    return linkbreakers.NewAPIClient(config)
}

type CreateLinkRequest struct {
    Destination string   `json:"destination"`
    Name        string   `json:"name"`
    Tags        []string `json:"tags"`
}

func main() {
    e := echo.New()
    client := getClient()

    e.POST("/api/create-link", func(c echo.Context) error {
        var req CreateLinkRequest
        if err := c.Bind(&req); err != nil {
            return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
        }

        createReq := linkbreakers.NewCreateLinkRequest(req.Destination)
        if req.Name != "" {
            createReq.SetName(req.Name)
        }
        if len(req.Tags) > 0 {
            createReq.SetTags(req.Tags)
        }

        response, _, err := client.LinksAPI.LinksServiceCreate(context.Background()).
            CreateLinkRequest(*createReq).
            Execute()

        if err != nil {
            return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
        }

        return c.JSON(http.StatusOK, map[string]interface{}{
            "success":   true,
            "shortlink": response.Link.GetShortlink(),
            "qr_code":   response.Link.GetQrcodeSignedUrl(),
        })
    })

    e.Logger.Fatal(e.Start(":8080"))
}
```

## Error handling

Implement proper error handling for production:

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/linkbreakers-com/linkbreakers-go"
)

func createLinkWithErrorHandling(client *linkbreakers.APIClient) {
    ctx := context.Background()

    createReq := linkbreakers.NewCreateLinkRequest("https://example.com/page")
    createReq.SetName("My Link")

    response, httpResp, err := client.LinksAPI.LinksServiceCreate(ctx).
        CreateLinkRequest(*createReq).
        Execute()

    if err != nil {
        if httpResp != nil {
            log.Printf("API Error: Status %d\n", httpResp.StatusCode)
        }
        log.Fatalf("Error creating link: %v", err)
        return
    }

    fmt.Printf("Success: %s\n", response.Link.GetShortlink())
}
```

To let an AI agent drive the Go SDK, or to use the MCP server instead, see [How Linkbreakers works with AI agents](/help/article/linkbreakers-for-ai-agents).

## Frequently asked questions

**Can I use the Go SDK with popular web frameworks?**

Yes! The SDK is framework-agnostic and works seamlessly with Gin, Echo, Fiber, Chi, and any Go web framework.

**How do I handle rate limits?**

The SDK will return errors if you exceed rate limits. Implement exponential backoff retry logic for production applications.

**Does the SDK support concurrency?**

Yes, the SDK is safe for concurrent use. You can create multiple goroutines that share the same API client.

**How do I get the LBID for visitor identification?**

The LBID appears as a `?lbid=` query parameter when visitors click your links with conversion tracking enabled. Extract it from request parameters and pass it to `VisitorsServiceIdentify()`.

**Can I create bulk links efficiently?**

Yes, use `LinksServiceCreateBulk()` to create up to 1000 links in a single API call, which is much more efficient than individual requests.

**What Go versions are supported?**

The SDK supports Go 1.18+ with full support for generics and modern Go features.

**How do I test without affecting production data?**

Create a [sandbox](/help/article/sandbox-test-environment) from **Dashboard → API Tokens → Sandboxes**, or with `POST /v1/sandboxes`. A sandbox is a separate, empty workspace whose token starts with `lb_test_`, so it can never touch your live links or analytics, its usage is never billed, and it is deleted 30 days after creation.

## Sources

- [Linkbreakers Go SDK GitHub Repository](https://github.com/linkbreakers-com/linkbreakers-go)
- [What is LBID?](https://linkbreakers.com/help/article/what-is-the-linkbreakers-id-lbid)
- [Linkbreakers API Documentation](https://linkbreakers.com/help/article/how-to-use-the-linkbreakers-api)

## Last reviewed

This article was last reviewed on March 31, 2025.
