SDKs

Go SDK

Use idiomatic Go packages to discover Services, navigate catalogs, or publish ODP through the standard HTTP stack.

The official SDK is developed in the odp-go GitHub repository. The module and its API reference are published on pkg.go.dev.

Choose the package for your role

One Go module contains four packages with narrow responsibilities. Import only the role packages the application uses; each role depends on the root protocol package as needed.

PackageUse it when
odpProtocol models, validation, references, identities, and pagination are needed directly.
agentAn Agent inspects Services, navigates catalogs, or discovers Offerings across Directory results.
directoryAn application searches the fixed production or sandbox Directory directly.
serviceA Service publishes its document and catalog through net/http.

Install the SDK

The module requires Go 1.25 or newer. One module dependency supplies the root, Agent, Directory, and Service packages at a compatible version.

go get github.com/offering-protocol/odp-go@latest

Navigate a known Service

agent.ServiceClient validates the well-known document and checks each advertised operation before sending a catalog request. Lazy Go iterators allow the caller to stop traversal without loading the complete catalog.

import (
	"context"
	"fmt"

	"github.com/offering-protocol/odp-go/agent"
)

ctx := context.Background()
client, err := agent.NewServiceClient(agent.ServiceClientOptions{
	ServiceURL: "https://demo.inflowpay.ai",
})
if err != nil {
	return err
}

inspection, err := client.Inspect(ctx)
if err != nil {
	return err
}
fmt.Println(inspection.Document.Name)

for offering, err := range client.ListOfferings(ctx, agent.ListOptions{MaxItems: 10}) {
	if err != nil {
		return err
	}
	fmt.Println(offering.ID, offering.Name)
	details, err := client.GetOfferingDetails(ctx, offering.ID)
	if err != nil {
		return err
	}
	for _, action := range details.Actions {
		fmt.Println("Action", action.ID, action.Rel)
	}
}

Use the page methods when continuation links, refinements, or other page metadata are needed. Full Offering details resolve Attribute Schemas and normalize usable Actions without invoking them.

Discover across Services

agent.Agent searches the canonical Directory and queries live Service catalogs with bounded concurrency. Filter candidate Services by the operation the Offering request will use.

import (
	"context"
	"fmt"

	odp "github.com/offering-protocol/odp-go"
	"github.com/offering-protocol/odp-go/agent"
	"github.com/offering-protocol/odp-go/directory"
)

ctx := context.Background()
odpAgent, err := agent.New(agent.AgentOptions{
	Environment: directory.Sandbox,
})
if err != nil {
	return err
}

request := agent.FederatedSearchRequest{
	Services: directory.SearchRequest{
		Filters: &directory.ServiceFilters{
			Keywords: []string{"search"},
			Operations: []directory.OperationFilter{{
				Name: odp.OperationSearchOfferings,
			}},
		},
	},
	Offerings: agent.OfferingSearchOptions{Query: "web research"},
}

for event, err := range odpAgent.SearchOfferingsAcrossServices(ctx, request) {
	if err != nil {
		return err
	}
	switch event.Type {
	case agent.DiscoveryOffering:
		fmt.Println(event.Service.Name, event.Offering.Name)
	case agent.DiscoveryIssue:
		fmt.Println(event.Service.ServiceOrigin, event.Err)
	}
}

Results preserve Directory order. An unavailable or incompatible Service becomes an issue event without discarding successful Offerings from other Services.

Publish a small Service

service.NewStaticCatalog provides the required Offering operations for a bounded in-memory catalog. service.Service implements http.Handler and derives its advertised operations from the configured catalog functions.

import (
	"net/http"

	odp "github.com/offering-protocol/odp-go"
	"github.com/offering-protocol/odp-go/service"
)

catalog, err := service.NewStaticCatalog(service.StaticCatalogOptions{
	Offerings: []odp.Offering{{
		ID:         "web-search",
		Name:       "Web search",
		ODPVersion: odp.Version,
	}},
})
if err != nil {
	return err
}

odpService, err := service.New(service.Options{
	Catalog: catalog,
	Document: odp.ServiceDocument{
		Description:   "Research tools for Agents.",
		HTTP:          odp.HTTPConfiguration{EndpointBase: "/odp"},
		Language:      "en",
		Localizations: []string{"en"},
		Name:          "Example Research Service",
	},
})
if err != nil {
	return err
}

mux := http.NewServeMux()
mux.Handle("/.well-known/odp", odpService)
mux.Handle("/odp/", odpService)

Mount the same handler at /.well-known/odp and the configured endpoint base. Authentication, payments, authorization, and rate limiting remain ordinary middleware around that handler.

See the Minimum service for the required Service Document and Offering operations represented by this configuration.

Connect a production catalog

Application-backed Services provide catalog functions that translate validated request context into storage queries. The configured optional functions also determine which optional operations the Service advertises.

import (
	odp "github.com/offering-protocol/odp-go"
	"github.com/offering-protocol/odp-go/service"
	"example.com/application/catalog"
)

func newService(repository *catalog.Repository, document odp.ServiceDocument) (*service.Service, error) {
	operations := service.Catalog{
		ListOfferings:   repository.ListOfferings,
		GetOffering:     repository.GetOffering,
		SearchOfferings: repository.SearchOfferings,
	}
	return service.New(service.Options{
		Catalog:  operations,
		Document: document,
	})
}

Each function receives cancellation, the original HTTP request, representation, language, limit, and cursor. The ODP runtime invokes only the function required for the incoming operation and never materializes the complete catalog.

Keep application responsibilities separate

  • Network policy: the default Agent transport rejects non-public destinations and unsafe redirects; an injected HTTP client owns equivalent protection
  • Authenticated caching: set a stable cache partition for each authenticated principal and access context
  • Action boundary: Action resolution returns validated metadata and never performs the Action
  • Service lifecycle: the hosting server owns shutdown, telemetry, persistence, and middleware

Run the examples

The odp-go repository includes a small public Service and an Agent that uses an explicitly labeled mock Directory while making real requests to reachable ODP Services.

  • Small Service: publish an in-memory catalog and a working free download Action through net/http
  • Agent discovery: inspect live Services and retrieve terse and full Offerings through mock Directory results

Next steps

Agent path

Discover a Service

Inspect a Service and navigate only the operations it advertises.

Discover a Service
Service path

Design the integration

Map the existing catalog before selecting static or storage-backed integration.

Build a Service