qrpro

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 24, 2026 License: MIT Imports: 15 Imported by: 0

README

qr-pro-go

Official Go SDK for Abundera QR Pro.

Dynamic QR codes that you actually own. Scan analytics. Webhooks. Privacy-safe by default.

Install

go get github.com/abundera/qr-pro-go

Requires Go 1.21+.

Quickstart

package main

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

    qrpro "github.com/abundera/qr-pro-go"
)

func main() {
    c, err := qrpro.New(os.Getenv("ABUNDERA_API_KEY"))
    if err != nil {
        log.Fatal(err)
    }
    ctx := context.Background()

    code, err := c.CreateCode(ctx, qrpro.CodeCreate{
        DestinationURL: "https://example.com/launch",
        Label:          "Spring launch poster",
        Tags:           []string{"print", "q2"},
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(code.ShortURL)

    // Later: change where it points
    newDest := "https://example.com/launch/v2"
    _, _ = c.UpdateCode(ctx, code.ID, qrpro.CodePatch{DestinationURL: &newDest})

    // Pull analytics
    stats, _ := c.GetAnalytics(ctx, code.ID, &qrpro.AnalyticsParams{From: "2026-04-01"})
    fmt.Println(stats.TotalScans)
}

Webhook verification

import qrpro "github.com/abundera/qr-pro-go"

func handler(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    sig := r.Header.Get("X-Abundera-Signature")

    if err := qrpro.VerifyWebhookSignature(sig, body, os.Getenv("ABUNDERA_WEBHOOK_SECRET"), 0); err != nil {
        http.Error(w, "bad signature", http.StatusBadRequest)
        return
    }
    // safe to parse and act on body
}

Configuration

c, _ := qrpro.New(apiKey,
    qrpro.WithBaseURL("https://pro.qr.abundera.ai"),
    qrpro.WithHTTPClient(&http.Client{Timeout: 60 * time.Second}),
    qrpro.WithMaxRetries(5),
    qrpro.WithUserAgent("myapp/1.2.3"),
)

Error handling

Non-2xx responses (after retries) return a *qrpro.Error:

code, err := c.CreateCode(ctx, qrpro.CodeCreate{DestinationURL: "not a url"})
if err != nil {
    var apiErr *qrpro.Error
    if errors.As(err, &apiErr) {
        log.Printf("status=%d code=%s msg=%s req=%s", apiErr.Status, apiErr.Code, apiErr.Message, apiErr.RequestID)
    }
}

Coverage

Supported surfaces: codes (CRUD + slug check), analytics (JSON + CSV), groups, webhooks, user. See API docs for the full OpenAPI 3.1 spec.

License

MIT © Abundera, Inc.

Documentation

Overview

Package qrpro is the official Go SDK for Abundera QR Pro.

See https://pro.qr.abundera.ai/docs/ for the full API reference.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func VerifyWebhookSignature

func VerifyWebhookSignature(signature string, body []byte, secret string, toleranceSeconds int) error

VerifyWebhookSignature verifies a Stripe-compatible webhook signature of the form: "t=<unix_ts>,v1=<hex>". It recomputes HMAC-SHA256 of "{t}.{body}" with secret and compares in constant time. Returns nil on success or an error on mismatch / timestamp skew > toleranceSeconds.

Pass 0 for toleranceSeconds to use the default (300s).

Types

type Analytics

type Analytics struct {
	CodeID     string `json:"code_id"`
	TotalScans int    `json:"total_scans"`
	UniqueDays int    `json:"unique_days"`
	ByDay      []struct {
		Date  string `json:"date"`
		Scans int    `json:"scans"`
	} `json:"by_day"`
	ByCountry []struct {
		Country string `json:"country"`
		Scans   int    `json:"scans"`
	} `json:"by_country"`
	ByDevice []struct {
		DeviceClass string `json:"device_class"`
		Scans       int    `json:"scans"`
	} `json:"by_device"`
}

type AnalyticsParams

type AnalyticsParams struct{ From, To string }

type Client

type Client struct {
	APIKey     string
	BaseURL    string
	HTTPClient *http.Client
	MaxRetries int
	UserAgent  string
}

Client is the Abundera QR Pro API client.

func New

func New(apiKey string, opts ...Option) (*Client, error)

New returns a Client authenticated with apiKey.

func (*Client) CheckSlug

func (c *Client) CheckSlug(ctx context.Context, slug string) (bool, error)

func (*Client) CreateCode

func (c *Client) CreateCode(ctx context.Context, in CodeCreate) (*Code, error)

func (*Client) CreateGroup

func (c *Client) CreateGroup(ctx context.Context, name, description string) (*Group, error)

func (*Client) CreateWebhook

func (c *Client) CreateWebhook(ctx context.Context, webhookURL string, events []string) (*Webhook, error)

CreateWebhook returns a Webhook with Secret populated — store it immediately.

func (*Client) DeleteCode

func (c *Client) DeleteCode(ctx context.Context, id string) error

func (*Client) DeleteGroup

func (c *Client) DeleteGroup(ctx context.Context, id string) error

func (*Client) DeleteWebhook

func (c *Client) DeleteWebhook(ctx context.Context, id string) error

func (*Client) GetAnalytics

func (c *Client) GetAnalytics(ctx context.Context, codeID string, p *AnalyticsParams) (*Analytics, error)

func (*Client) GetAnalyticsCSV

func (c *Client) GetAnalyticsCSV(ctx context.Context, codeID string, p *AnalyticsParams) (string, error)

func (*Client) GetCode

func (c *Client) GetCode(ctx context.Context, id string) (*Code, error)

func (*Client) ListCodes

func (c *Client) ListCodes(ctx context.Context, params *ListCodesParams) (*ListResult[Code], error)

func (*Client) ListGroups

func (c *Client) ListGroups(ctx context.Context) (*ListResult[Group], error)

func (*Client) ListWebhooks

func (c *Client) ListWebhooks(ctx context.Context) (*ListResult[Webhook], error)

func (*Client) Me

func (c *Client) Me(ctx context.Context) (map[string]any, error)

func (*Client) UpdateCode

func (c *Client) UpdateCode(ctx context.Context, id string, patch CodePatch) (*Code, error)

type Code

type Code struct {
	ID             string   `json:"id"`
	Slug           string   `json:"slug"`
	DestinationURL string   `json:"destination_url"`
	Label          string   `json:"label,omitempty"`
	Tags           []string `json:"tags,omitempty"`
	GroupID        *string  `json:"group_id,omitempty"`
	CreatedAt      string   `json:"created_at"`
	UpdatedAt      string   `json:"updated_at"`
	ScanCount      int      `json:"scan_count,omitempty"`
	LastScanAt     *string  `json:"last_scan_at,omitempty"`
	Active         bool     `json:"active"`
	ShortURL       string   `json:"short_url"`
}

type CodeCreate

type CodeCreate struct {
	DestinationURL string   `json:"destination_url"`
	Slug           string   `json:"slug,omitempty"`
	Label          string   `json:"label,omitempty"`
	Tags           []string `json:"tags,omitempty"`
	GroupID        *string  `json:"group_id,omitempty"`
}

type CodePatch

type CodePatch struct {
	DestinationURL *string  `json:"destination_url,omitempty"`
	Label          *string  `json:"label,omitempty"`
	Tags           []string `json:"tags,omitempty"`
	GroupID        *string  `json:"group_id,omitempty"`
	Active         *bool    `json:"active,omitempty"`
}

type Error

type Error struct {
	Status    int    `json:"status"`
	Code      string `json:"code"`
	Message   string `json:"message"`
	RequestID string `json:"request_id,omitempty"`
}

Error is returned for any non-2xx API response.

func (*Error) Error

func (e *Error) Error() string

type Group

type Group struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	CreatedAt   string `json:"created_at"`
	CodeCount   int    `json:"code_count,omitempty"`
}

type ListCodesParams

type ListCodesParams struct {
	Cursor  string
	Limit   int
	Tag     string
	GroupID string
}

type ListResult

type ListResult[T any] struct {
	Data       []T        `json:"data"`
	Pagination Pagination `json:"pagination"`
}

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(u string) Option

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

func WithMaxRetries

func WithMaxRetries(n int) Option

func WithUserAgent

func WithUserAgent(ua string) Option

type Pagination

type Pagination struct {
	Cursor  *string `json:"cursor,omitempty"`
	Limit   int     `json:"limit,omitempty"`
	HasMore bool    `json:"has_more,omitempty"`
}

type Webhook

type Webhook struct {
	ID        string   `json:"id"`
	URL       string   `json:"url"`
	Events    []string `json:"events"`
	Active    bool     `json:"active"`
	CreatedAt string   `json:"created_at"`
	Secret    string   `json:"secret,omitempty"` // only on creation
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL