trackofferz

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 12 Imported by: 0

README

trackofferz-go

Official Go SDK for the TrackOfferz reporting API.

  • Idiomaticcontext.Context, typed errors, generics for pages.
  • Zero dependencies — standard library only.
  • Resilient — auto-retry on 429 (honours Retry-After) and transient 5xx.
  • Network-scoped — every call is limited to your network by the API key.

Install

go get github.com/mecorpking/trackofferz-go@latest

Authenticate

Create a key in the panel under Settings → API keys (format tofz_sk_…).

import "github.com/mecorpking/trackofferz-go"

client, err := trackofferz.New("tofz_sk_...")

Reporting

ctx := context.Background()

// Summary (defaults to the last 30 days)
s, _ := client.Reports.Summary(ctx, trackofferz.SummaryParams{
    From: "2026-06-01", To: "2026-06-30",
})
fmt.Println(s.Clicks, s.Conversions, s.RevenueCents)

// Breakdown by publisher
rows, _ := client.Reports.Breakdown(ctx, trackofferz.BreakdownParams{By: "publisher"})
for _, r := range rows {
    fmt.Println(r.Label, r.Conversions, r.PayoutCents)
}

// One page of conversions for a campaign
page, _ := client.Reports.Conversions(ctx, trackofferz.ConversionParams{
    CampaignID: 5, Page: 1, PageSize: 100,
})
fmt.Println(page.Total, page.HasNext())

// Stream EVERY click across all pages (auto-pagination)
_ = client.Reports.IterClicks(ctx, trackofferz.ClickParams{From: "2026-06-01"},
    func(c trackofferz.ClickRow) error {
        fmt.Println(c.TransactionID, c.CountryCode, c.IsUnique)
        return nil
    })

Money fields are integers in cents (PayoutCents 1250 → $12.50). Dates are YYYY-MM-DD.

Conversions (ingest)

Record a conversion server-to-server for a click your link already tracked — the basis of "Track from CMS". TransactionID is the click id captured on your landing page.

res, err := client.Conversions.Create(ctx, trackofferz.ConversionInput{
    TransactionID: "click_abc123",        // the click id (a.k.a. tid)
    EventType:     "purchase",            // default; also: lead, install, refund, …
    Payout:        trackofferz.Money(12.50), // decimal, or PayoutCents: trackofferz.Cents(1250)
    SaleAmount:    trackofferz.Money(199.00),
    Currency:      "USD",
    CustomData:    map[string]any{"order_id": "SO-9001"},
})
if err != nil {
    if trackofferz.IsValidation(err) { /* bad input */ }
    log.Fatal(err)
}
fmt.Println(res.Status, res.ConversionID, res.Duplicate)

Idempotent. Re-sending the same TransactionID returns the existing conversion with Duplicate == true — it never double-counts. Retries on 429/5xx are therefore safe and automatic.

The key is bound to your network: you can only convert your own clicks. A 404 (Error.Code == "click_not_found") means no click matched the TransactionID within the attribution window. Money fields use the trackofferz.Money(...) / trackofferz.Cents(...) pointer helpers so a zero payout is distinguishable from "unset".

Errors

_, err := client.Reports.Summary(ctx, trackofferz.SummaryParams{From: "not-a-date"})
switch {
case trackofferz.IsValidation(err):
    log.Println("bad input")
case trackofferz.IsRateLimited(err):
    log.Println("slow down")
case err != nil:
    var e *trackofferz.Error
    errors.As(err, &e)
    log.Println(e.StatusCode, e.Code, e.Message)
}

Options

client, _ := trackofferz.New("tofz_sk_...",
    trackofferz.WithBaseURL("https://trackofferz.com/api/v1"), // self-hosted override
    trackofferz.WithTimeout(30*time.Second),
    trackofferz.WithMaxRetries(2),
)

Full API reference: https://trackofferz.com/docs


TrackOfferz is a product by SPTSPL (S. P. Techno Solution Private Limited).

Documentation

Overview

Package trackofferz is the official Go SDK for the TrackOfferz reporting API.

client, _ := trackofferz.New("tofz_sk_...")
s, err := client.Reports.Summary(ctx, trackofferz.SummaryParams{From: "2026-06-01", To: "2026-06-30"})

Create a key in the panel under Settings → API keys. Every call is scoped to your network. Docs: https://trackofferz.com/docs

Index

Examples

Constants

View Source
const Version = "0.2.0"

Version of the SDK (sent as the User-Agent).

Variables

This section is empty.

Functions

func Cents

func Cents(v int) *int

Cents returns a *int for the *Cents params.

func IsAuth

func IsAuth(err error) bool

IsAuth reports whether err is a 401 (invalid/missing/revoked key).

func IsRateLimited

func IsRateLimited(err error) bool

IsRateLimited reports whether err is a 429.

func IsValidation

func IsValidation(err error) bool

IsValidation reports whether err is a 422 (bad request parameters).

func Money

func Money(v float64) *float64

Money returns a *float64 for the decimal money params.

Types

type BreakdownParams

type BreakdownParams struct {
	By   string // default "campaign"
	From string
	To   string
}

BreakdownParams groups by By ∈ {"campaign","publisher","country","sub_id"}.

type BreakdownRow

type BreakdownRow struct {
	Key          string  `json:"key"`
	Label        *string `json:"label"`
	Clicks       int     `json:"clicks"`
	UniqueClicks int     `json:"unique_clicks"`
	Conversions  int     `json:"conversions"`
	PayoutCents  int     `json:"payout_cents"`
	RevenueCents int     `json:"revenue_cents"`
}

type ClickParams

type ClickParams struct {
	From            string
	To              string
	CampaignID      int
	PublisherID     int
	Page            int // 0 → 1
	PageSize        int // 0 → 100, max 1000
	IncludeRejected bool
}

type ClickRow

type ClickRow struct {
	EventTime     string   `json:"event_time"`
	TransactionID string   `json:"transaction_id"`
	CampaignID    int      `json:"campaign_id"`
	PublisherID   int      `json:"publisher_id"`
	CountryCode   string   `json:"country_code"`
	Region        string   `json:"region"`
	City          string   `json:"city"`
	OS            string   `json:"os"`
	Browser       string   `json:"browser"`
	DeviceType    string   `json:"device_type"`
	IPAddress     string   `json:"ip_address"`
	ASN           int      `json:"asn"`
	ISP           string   `json:"isp"`
	SubIDs        []string `json:"sub_ids"`
	IsUnique      bool     `json:"is_unique"`
	FraudScore    int      `json:"fraud_score"`
	Rejected      bool     `json:"rejected"`
	RejectionCode string   `json:"rejection_code"`
}

type Client

type Client struct {

	// Reports holds the reporting endpoints.
	Reports *ReportsService
	// Conversions records conversions server-to-server (SDK / CMS ingest).
	Conversions *ConversionsService
	// contains filtered or unexported fields
}

Client is the entry point. Construct with New and use its services.

Example (Reports)

Compile-only doc example (no Output comment → not executed by `go test`).

package main

import (
	"context"
	"fmt"

	"github.com/mecorpking/trackofferz-go"
)

func main() {
	client, err := trackofferz.New("tofz_sk_...")
	if err != nil {
		panic(err)
	}

	ctx := context.Background()
	s, err := client.Reports.Summary(ctx, trackofferz.SummaryParams{
		From: "2026-06-01",
		To:   "2026-06-30",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(s.Clicks, s.Conversions)
}

func New

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

New builds a Client. apiKey must be a TrackOfferz key (starts with "tofz_").

type ConversionInput

type ConversionInput struct {
	TransactionID string `json:"transaction_id"`

	EventType string `json:"event_type,omitempty"` // default "purchase"
	EventID   int    `json:"event_id,omitempty"`   // default 1

	Payout          *float64 `json:"payout,omitempty"`
	PayoutCents     *int     `json:"payout_cents,omitempty"`
	SaleAmount      *float64 `json:"sale_amount,omitempty"`
	SaleAmountCents *int     `json:"sale_amount_cents,omitempty"`
	AdvertiserCost  *float64 `json:"advertiser_cost,omitempty"`

	Currency   string         `json:"currency,omitempty"`
	Status     string         `json:"status,omitempty"` // APPROVED | PENDING | REJECTED
	CustomData map[string]any `json:"custom_data,omitempty"`
}

ConversionInput is the input to Create. TransactionID is required and is the click id captured on your landing page; it is also the idempotency key.

Money may be supplied as a decimal (Payout: 12.50) OR in cents (PayoutCents: 1250). Cents wins if both are set. Pointer fields are omitted from the request when nil, so a zero payout is distinguishable from "unset".

type ConversionParams

type ConversionParams struct {
	From        string
	To          string
	CampaignID  int
	PublisherID int
	Page        int
	PageSize    int
}

type ConversionResult

type ConversionResult struct {
	OK            bool   `json:"ok"`
	TransactionID string `json:"transaction_id"`
	ConversionID  *int64 `json:"conversion_id"`
	EventID       *int64 `json:"event_id"`
	EventType     string `json:"event_type"`
	Status        string `json:"status"`
	// Duplicate is true when this transaction_id was already recorded (an
	// idempotent replay) — no new conversion was created.
	Duplicate     bool `json:"duplicate"`
	RefundApplied bool `json:"refund_applied"`
}

ConversionResult is the outcome of Create.

type ConversionRow

type ConversionRow struct {
	EventTime           string `json:"event_time"`
	TransactionID       string `json:"transaction_id"`
	CampaignID          int    `json:"campaign_id"`
	PublisherID         int    `json:"publisher_id"`
	EventType           string `json:"event_type"`
	Status              string `json:"status"`
	PayoutCents         int    `json:"payout_cents"`
	SaleAmountCents     int    `json:"sale_amount_cents"`
	AdvertiserCostCents int    `json:"advertiser_cost_cents"`
	Currency            string `json:"currency"`
	CountryCode         string `json:"country_code"`
	CtitSeconds         int    `json:"ctit_seconds"`
}

type ConversionsService

type ConversionsService struct {
	// contains filtered or unexported fields
}

ConversionsService records conversions server-to-server (the "Track from CMS" ingest surface). Access it via Client.Conversions.

func (*ConversionsService) Create

Create records a conversion for p.TransactionID. Idempotent: re-sending the same transaction_id returns the existing conversion with Duplicate=true and never double-counts. The key is bound to your network, so you can only convert your own clicks.

Use IsAuth / IsValidation / IsRateLimited to classify *Error returns; a 404 (Error.Code == "click_not_found") means no click matched the transaction_id.

type DateRange

type DateRange struct {
	From string `json:"from"`
	To   string `json:"to"`
}

type Error

type Error struct {
	StatusCode int
	Code       string
	Message    string
	// RetryAfter is set (seconds) on 429 responses when the server supplies it.
	RetryAfter int
}

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

func (*Error) Error

func (e *Error) Error() string

type Option

type Option func(*Client)

Option configures the Client.

func WithBaseURL

func WithBaseURL(u string) Option

WithBaseURL overrides the API base (e.g. for a self-hosted instance).

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient supplies a custom *http.Client (proxies, custom transport…).

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets retries for 429 / transient 5xx (default 2).

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the per-request timeout (default 30s).

type Page

type Page[T any] struct {
	Rows []T
	Pagination
}

Page is a slice of rows plus its pagination cursor.

type Pagination

type Pagination struct {
	Page       int `json:"page"`
	PageSize   int `json:"page_size"`
	Total      int `json:"total"`
	TotalPages int `json:"total_pages"`
}

func (Pagination) HasNext

func (p Pagination) HasNext() bool

HasNext reports whether more pages remain after this one.

type ReportsService

type ReportsService struct {
	// contains filtered or unexported fields
}

ReportsService exposes the reporting endpoints. Access via Client.Reports.

func (*ReportsService) Breakdown

func (s *ReportsService) Breakdown(ctx context.Context, p BreakdownParams) ([]BreakdownRow, error)

Breakdown returns performance grouped by one dimension.

func (*ReportsService) Clicks

func (s *ReportsService) Clicks(ctx context.Context, p ClickParams) (*Page[ClickRow], error)

Clicks returns one page of click detail (newest first).

func (*ReportsService) Conversions

Conversions returns one page of conversion detail (newest first; refunds excluded).

func (*ReportsService) IterClicks

func (s *ReportsService) IterClicks(ctx context.Context, p ClickParams, fn func(ClickRow) error) error

IterClicks calls fn for every click across all pages. Return a non-nil error from fn to stop early. Defaults to 1000 rows/page if PageSize is 0.

func (*ReportsService) IterConversions

func (s *ReportsService) IterConversions(ctx context.Context, p ConversionParams, fn func(ConversionRow) error) error

IterConversions calls fn for every conversion across all pages.

func (*ReportsService) Summary

func (s *ReportsService) Summary(ctx context.Context, p SummaryParams) (*Summary, error)

Summary returns aggregate totals over a date range.

type Summary

type Summary struct {
	Range           DateRange `json:"range"`
	Clicks          int       `json:"clicks"`
	UniqueClicks    int       `json:"unique_clicks"`
	Conversions     int       `json:"conversions"`
	ConversionRate  float64   `json:"conversion_rate"`
	PayoutCents     int       `json:"payout_cents"`
	RevenueCents    int       `json:"revenue_cents"`
	SaleAmountCents int       `json:"sale_amount_cents"`
}

Money fields are integers in CENTS (PayoutCents 1250 → $12.50).

type SummaryParams

type SummaryParams struct {
	From        string // YYYY-MM-DD
	To          string // YYYY-MM-DD
	CampaignID  int    // 0 = all
	PublisherID int    // 0 = all
}

SummaryParams filters a summary. Zero-value fields are omitted (the API applies its defaults: last 30 days, all campaigns/publishers).

Jump to

Keyboard shortcuts

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