Skip to content

Go SDK

Go SDK

The github.com/verbitas/sdk-go module is the official Go client for the Verbitas API.

  • Module: github.com/verbitas/sdk-go
  • Go: 1.23+
  • License: MIT

Installation

Terminal window
go get github.com/verbitas/sdk-go

Configuration

package main
import (
verbitas "github.com/verbitas/sdk-go"
)
func main() {
// From environment variable VERBITAS_API_KEY (recommended)
client := verbitas.NewClient("")
// Explicit key
client := verbitas.NewClient("vb_live_01j...")
// With options
client := verbitas.NewClientWithOptions(verbitas.ClientOptions{
APIKey: os.Getenv("VERBITAS_API_KEY"),
BaseURL: "https://api.verbitas.io",
Timeout: 60 * time.Second,
MaxRetries: 3,
})
}

Signing

package main
import (
"context"
"fmt"
verbitas "github.com/verbitas/sdk-go"
)
func main() {
client := verbitas.NewClient("")
result, err := client.Sign(context.Background(), "output.png", &verbitas.SignOptions{
Recipe: "image-genai-v1",
Metadata: map[string]string{
"generator": "stable-diffusion-xl",
"model": "sdxl-1.0",
},
})
if err != nil {
// see error handling section
panic(err)
}
fmt.Println(result.AssetID) // "a_01j..."
fmt.Println(result.VerifierURL) // "https://v.verbitas.io/v/a_01j..."
fmt.Println(result.ManifestURI) // "https://m.verbitas.io/manifests/..."
}

Sign from io.Reader

f, err := os.Open("output.png")
if err != nil {
panic(err)
}
defer f.Close()
result, err := client.SignReader(context.Background(), f, &verbitas.SignReaderOptions{
Recipe: "image-genai-v1",
Filename: "output.png",
})

Large files (async)

Large files return a job ID. Use WaitForJob to poll:

job, err := client.SignAsync(context.Background(), "large_video.mp4", &verbitas.SignOptions{
Recipe: "video-genai-v1",
})
if err != nil {
panic(err)
}
result, err := client.WaitForJob(context.Background(), job.JobID, &verbitas.WaitOptions{
Timeout: 5 * time.Minute,
PollInterval: 2 * time.Second,
})

Or use Sign which handles async transparently:

// Sign handles polling automatically for large files
result, err := client.Sign(context.Background(), "large_video.mp4", &verbitas.SignOptions{
Recipe: "video-genai-v1",
WaitSync: true, // block until done (default true)
})

Verifying

// By file path
result, err := client.Verify(context.Background(), &verbitas.VerifyOptions{
FilePath: "received_image.jpg",
})
// By asset ID
result, err := client.Verify(context.Background(), &verbitas.VerifyOptions{
AssetID: "a_01j...",
})
// By manifest URI
result, err := client.Verify(context.Background(), &verbitas.VerifyOptions{
ManifestURI: "https://m.verbitas.io/manifests/a_01j.../manifest.c2pa",
})
if err != nil {
panic(err)
}
fmt.Println(result.Status) // "verified_manifest_and_watermark_match"
fmt.Println(result.Confidence) // 0.97

Status constants

switch result.Status {
case verbitas.StatusVerifiedManifestAndWatermarkMatch,
verbitas.StatusVerifiedManifestIntact:
// proceed
case verbitas.StatusManifestTampered:
return fmt.Errorf("asset tampered: %s", result.DeveloperExplanation)
case verbatas.StatusNoProvenance:
// no record found
}

Lookup

result, err := client.Lookup(context.Background(), &verbitas.LookupOptions{
FilePath: "cropped_image.jpg",
})
if err != nil {
panic(err)
}
for _, match := range result.Matches {
fmt.Printf("%s %s %.2f\n", match.AssetID, match.MatchType, match.Confidence)
}

Recipes

// List
recipes, err := client.Recipes.List(context.Background())
// Get
recipe, err := client.Recipes.Get(context.Background(), "image-genai-v1")
// Create (requires admin key)
yamlBytes, _ := os.ReadFile("my-recipe-v1.yaml")
created, err := client.Recipes.Create(context.Background(), string(yamlBytes))

Context support

All methods accept context.Context as the first argument. Use this for cancellation and deadlines:

ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
result, err := client.Sign(ctx, "output.png", &verbitas.SignOptions{
Recipe: "image-genai-v1",
})

Error handling

import (
"errors"
verbitas "github.com/verbitas/sdk-go"
)
result, err := client.Sign(ctx, "image.png", &verbitas.SignOptions{Recipe: "image-genai-v1"})
if err != nil {
var apiErr *verbitas.APIError
if errors.As(err, &apiErr) {
switch apiErr.Code {
case "verbitas.auth.invalid_key":
log.Printf("invalid API key")
case "verbitas.billing.quota_exceeded":
log.Printf("monthly quota exceeded")
case "verbitas.ratelimit.exceeded":
log.Printf("rate limited; retry after %s", apiErr.RetryAfter)
default:
log.Printf("API error %s: %s (request_id=%s)",
apiErr.Code, apiErr.Detail, apiErr.RequestID)
}
return
}
// network error, timeout, etc.
log.Printf("error: %v", err)
}

Retries

The client automatically retries on 429 and 5xx responses with exponential backoff. The default is 3 retries. Configure with ClientOptions.MaxRetries.

Idempotency keys are generated automatically for each sign call. To provide your own:

result, err := client.Sign(ctx, "output.png", &verbitas.SignOptions{
Recipe: "image-genai-v1",
IdempotencyKey: "01926e7a-f2b3-7abc-8def-0123456789ab",
})

Environment variables

VariableDescription
VERBITAS_API_KEYAPI key
VERBITAS_BASE_URLOverride base URL