acp

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

README

Go SDK for the Agentic Commerce Protocol

Go Reference CI Status License

Go SDK for the Agentic Commerce Protocol (ACP), targeting the stable API version 2026-04-17.

go get github.com/sumup/acp

Packages

Package Use
acpcheckout Serve seller-hosted checkout sessions.
acpcart Serve seller-hosted pre-checkout carts.
acppayment Serve delegated payment tokenization.
acpauthentication Serve delegated 3DS authentication.
acpfeed Call an agent-hosted Feed API.
acpdiscovery Serve /.well-known/acp.json.
acpwebhook Send signed order lifecycle events.
acpauth Implement bearer-token authorization.
signature Verify optional signed ACP requests.
discount, extension Use generated extension models.

Server handlers

The checkout, cart, payment, and authentication packages expose a Provider interface and a net/http handler. Implement the interface, supply an acpauth.Authorizer, and mount the handler directly or into an existing http.ServeMux with WithServeMux.

These handlers validate JSON payloads and ACP headers. Send API-Version: 2026-04-17 and Authorization: Bearer <token> on authenticated service requests. Mutating checkout, cart, and delegated-payment requests also require Idempotency-Key; the OpenAPI definitions describe endpoint-specific exceptions. Discovery is public and does not use those headers.

Checkout example

Run the in-memory example:

go run ./examples/checkout

Create and complete a session with spec-valid minimal payloads:

curl -sS -X POST http://localhost:8080/checkout_sessions \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer demo-key' \
  -H 'API-Version: 2026-04-17' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  -d '{
        "line_items": [{"id": "latte"}],
        "currency": "eur",
        "capabilities": {}
      }'

curl -sS -X POST http://localhost:8080/checkout_sessions/<session_id>/complete \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer demo-key' \
  -H 'API-Version: 2026-04-17' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440001' \
  -d '{
        "payment_data": {
          "handler_id": "card_tokenized",
          "instrument": {
            "type": "card",
            "credential": {"type": "spt", "token": "spt_demo"}
          }
        }
      }'
Delegated payment example
go run ./examples/delegated_payment

In another terminal:

curl -sS -X POST http://localhost:8080/agentic_commerce/delegate_payment \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer demo-key' \
  -H 'API-Version: 2026-04-17' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440002' \
  -d '{
        "payment_method": {
          "type": "card",
          "card_number_type": "fpan",
          "number": "4242424242424242",
          "exp_month": "11",
          "exp_year": "2030",
          "display_last4": "4242",
          "display_card_funding_type": "credit",
          "metadata": {"issuer": "demo-bank"}
        },
        "allowance": {
          "reason": "one_time",
          "max_amount": 2000,
          "currency": "eur",
          "checkout_session_id": "cs_000001",
          "merchant_id": "demo-merchant",
          "expires_at": "2027-12-31T23:59:59Z"
        },
        "risk_signals": [],
        "metadata": {"source": "sample"}
      }'

Feed client

The stable Feed API is hosted by agents and called by merchants. It is a push model: merchants create feed metadata and partially upsert products by Product.id.

country := "US"
client, err := acpfeed.NewClientWithResponses(agentURL)
if err != nil {
	return err
}

response, err := client.CreateFeedWithResponse(ctx, acpfeed.CreateFeedRequest{
	TargetCountry: &country,
})
if err != nil {
	return err
}
if response.JSON201 == nil {
	return fmt.Errorf("create feed: %s", response.Status())
}

See the executable examples on pkg.go.dev for discovery, webhooks, request signing, and feed upserts.

Development

Generated files are built from the vendored stable ACP specifications. Edit the specs or generator configuration, then run:

make generate
make fmt
make lint
make test

License

Apache 2.0

Documentation

Overview

Package acp provides shared Agentic Commerce Protocol types and HTTP helpers.

The protocol-specific packages are:

APIVersion identifies the stable ACP specification implemented by this module. HTTP handlers validate that version and make the supported version available in protocol-level version errors.

Index

Examples

Constants

View Source
const APIVersion = "2026-04-17"

APIVersion identifies the published Agentic Commerce Protocol version implemented by this module. Service handlers validate this value in the API-Version request header and emit it on their responses.

Variables

This section is empty.

Functions

func ContextWithRequestContext

func ContextWithRequestContext(ctx context.Context, requestCtx *RequestContext) context.Context

ContextWithRequestContext returns a context containing requestCtx.

A nil requestCtx leaves ctx unchanged. A nil ctx is replaced with context.Background.

func ContextWithRequestContextFromRequest

func ContextWithRequestContextFromRequest(r *http.Request) (context.Context, error)

ContextWithRequestContextFromRequest reads and validates ACP headers from r, then returns a child of r.Context containing that metadata.

func WithInternal

func WithInternal(err error) errorOption

WithInternal sets an internal error that can be retrieved from Error for telemetry purposes.

func WithOffendingParam

func WithOffendingParam(jsonPath string) errorOption

WithOffendingParam sets the JSON path for the field that triggered the error.

func WithRetryAfter

func WithRetryAfter(d time.Duration) errorOption

WithRetryAfter specifies how long clients should wait before retrying.

func WithStatusCode

func WithStatusCode(status int) errorOption

WithStatusCode overrides the HTTP status code returned to the client.

func WithSupportedVersions

func WithSupportedVersions(versions []string) errorOption

WithSupportedVersions sets the supported protocol versions returned to clients.

Types

type Error

type Error struct {
	Type              ErrorType `json:"type"`
	Code              ErrorCode `json:"code"`
	Message           string    `json:"message"`
	Param             *string   `json:"param,omitempty"`
	SupportedVersions []string  `json:"supported_versions,omitempty"`

	Internal error `json:"-"`
	// contains filtered or unexported fields
}

Error represents a structured ACP error payload.

func NewHTTPError

func NewHTTPError(status int, typ ErrorType, code ErrorCode, message string, opts ...errorOption) *Error

NewHTTPError allows callers to control the status code explicitly.

Example
package main

import (
	"fmt"

	"github.com/sumup/acp"
)

func main() {
	err := acp.NewHTTPError(
		409,
		acp.InvalidRequest,
		acp.IdempotencyConflict,
		"idempotency key was already used with different parameters",
		acp.WithOffendingParam("$.line_items"),
	)

	fmt.Println(err.StatusCode(), err.Type, err.Code, *err.Param)
}
Output:
409 invalid_request idempotency_conflict $.line_items

func NewInvalidRequestError

func NewInvalidRequestError(message string, opts ...errorOption) *Error

NewInvalidRequestError builds a Bad Request ACP error payload.

func NewProcessingError

func NewProcessingError(message string, opts ...errorOption) *Error

NewProcessingError builds an Internal Server Error ACP error payload.

func NewRateLimitExceededError

func NewRateLimitExceededError(message string, opts ...errorOption) *Error

NewRateLimitExceededError builds a Too Many Requests ACP error payload.

func NewServiceUnavailableError

func NewServiceUnavailableError(message string, opts ...errorOption) *Error

NewServiceUnavailableError builds a Service Unavailable ACP error payload.

func (*Error) Error

func (e *Error) Error() string

Error makes *Error satisfy the stdlib error interface.

func (*Error) RetryAfter

func (e *Error) RetryAfter() time.Duration

RetryAfter returns the duration clients should wait before retrying.

func (*Error) StatusCode

func (e *Error) StatusCode() int

StatusCode returns the HTTP status associated with the error.

type ErrorCode

type ErrorCode string

ErrorCode is a machine-readable identifier for the specific failure.

const (
	DuplicateRequest       ErrorCode = "duplicate_request"        // Safe duplicate with the same idempotency key.
	IdempotencyConflict    ErrorCode = "idempotency_conflict"     // Same idempotency key but different parameters.
	IdempotencyKeyRequired ErrorCode = "idempotency_key_required" // Idempotency-Key header is missing.
	IdempotencyInFlight    ErrorCode = "idempotency_in_flight"    // Request with same idempotency key is still processing.
	InvalidCard            ErrorCode = "invalid_card"             // Credential failed basic validation (such as length or expiry).
	InvalidSignature       ErrorCode = "invalid_signature"        // Signature is missing or does not match the payload.
	SignatureRequired      ErrorCode = "signature_required"       // Signed requests are required but headers were missing.
	StaleTimestamp         ErrorCode = "stale_timestamp"          // Timestamp skew exceeded the allowed window.
	MissingAuthorization   ErrorCode = "missing_authorization"    // Authorization header missing.
	InvalidAuthorization   ErrorCode = "invalid_authorization"    // Authorization header malformed or API key invalid.
	MissingAPIVersion      ErrorCode = "missing_api_version"      // API-Version header missing.
	UnsupportedAPIVersion  ErrorCode = "unsupported_api_version"  // API-Version is not supported by this server.
	TooManyRequests        ErrorCode = "too_many_requests"
)

type ErrorType

type ErrorType string

ErrorType mirrors the ACP error.type field.

const (
	InvalidRequest     ErrorType = "invalid_request"     // Missing or malformed field.
	ProcessingError    ErrorType = "processing_error"    // Downstream gateway or network failure.
	RateLimitExceeded  ErrorType = "rate_limit_exceeded" // Too many requests.
	ServiceUnavailable ErrorType = "service_unavailable" // Temporary outage or maintenance.
)

type RequestContext

type RequestContext struct {
	// API Key used to make requests.
	//
	// Example: Bearer api_key_123
	Authorization string
	// The preferred locale for content like messages and errors.
	//
	// Example: en-US
	AcceptLanguage string
	// Information about the client making this request.
	//
	// Example: ChatGPT/2.0 (Mac OS X 15.0.1; arm64; build 0)
	UserAgent string
	// Key used to ensure requests are idempotent.
	//
	// Example: idempotency_key_123
	IdempotencyKey string
	// Unique key for each request for tracing purposes.
	//
	// Example: request_id_123
	RequestID string
	// Optional detached signature used to verify the request body.
	//
	// Example: eyJtZX...
	Signature string
	// Optional request-signing timestamp formatted as an RFC 3339 string.
	//
	// Example: 2025-09-25T10:30:00Z
	Timestamp string
	// API version.
	//
	// Example: 2026-04-17
	APIVersion string
}

RequestContext carries the standard ACP headers.

func RequestContextFromContext

func RequestContextFromContext(ctx context.Context) *RequestContext

RequestContextFromContext extracts the HTTP request metadata previously stored in the context.

func RequestContextFromRequest

func RequestContextFromRequest(r *http.Request) (*RequestContext, error)

RequestContextFromRequest reads the standard ACP headers from r and validates that API-Version identifies the version implemented by this module.

Example
package main

import (
	"fmt"
	"net/http/httptest"

	"github.com/sumup/acp"
)

func main() {
	req := httptest.NewRequest("POST", "/checkout_sessions", nil)
	req.Header.Set("API-Version", acp.APIVersion)
	req.Header.Set("Authorization", "Bearer api_key_123")
	req.Header.Set("Idempotency-Key", "idem_123")

	requestContext, err := acp.RequestContextFromRequest(req)
	if err != nil {
		panic(err)
	}

	fmt.Println(requestContext.APIVersion, requestContext.IdempotencyKey)
}
Output:
2026-04-17 idem_123

Directories

Path Synopsis
Package acpauth defines bearer-token authorization for ACP HTTP handlers.
Package acpauth defines bearer-token authorization for ACP HTTP handlers.
Package acpauthentication serves the ACP Delegated Authentication API.
Package acpauthentication serves the ACP Delegated Authentication API.
Package acpcart serves the seller-hosted ACP Cart API.
Package acpcart serves the seller-hosted ACP Cart API.
Package acpcheckout serves the seller-hosted ACP Agentic Checkout API.
Package acpcheckout serves the seller-hosted ACP Agentic Checkout API.
Package acpdiscovery serves the public ACP discovery document.
Package acpdiscovery serves the public ACP discovery document.
Package acpfeed provides models and an HTTP client for the ACP Feed API.
Package acpfeed provides models and an HTTP client for the ACP Feed API.
Package acppayment serves the ACP Delegated Payment API.
Package acppayment serves the ACP Delegated Payment API.
Package acpwebhook sends ACP order lifecycle events to agent endpoints.
Package acpwebhook sends ACP order lifecycle events to agent endpoints.
Package discount provides models generated from the stable ACP discount extension schema.
Package discount provides models generated from the stable ACP discount extension schema.
examples
checkout command
Package extension provides models generated from the stable ACP extension registry schema.
Package extension provides models generated from the stable ACP extension registry schema.
internal
srv
Package signature provides low-level helpers for optional signed ACP request headers.
Package signature provides low-level helpers for optional signed ACP request headers.

Jump to

Keyboard shortcuts

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