vtex

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package vtex is a client for the public VTEX storefront APIs: catalog search, checkout orderForm, delivery simulation, VTEX ID auth, and order history.

Nothing here is store-specific. Every store-dependent value comes from the store.Store descriptor the client is constructed with.

Index

Constants

View Source
const (
	SubscriptionActive   = "ACTIVE"
	SubscriptionPaused   = "PAUSED"
	SubscriptionCanceled = "CANCELED"
	SubscriptionExpired  = "EXPIRED"
	SubscriptionMissing  = "MISSING"
)

Subscription statuses reported by the RNS API. CANCELED is terminal, which is why this package exposes no way to reach it.

View Source
const DefaultWishlistName = "Wishlist"

DefaultWishlistName is the list vtex.wish-list writes to when the storefront's heart icon is used.

Variables

View Source
var ErrAccessKeyRequired = errors.New("store requires an emailed access code")

ErrAccessKeyRequired reports that the only login method the store offers is an emailed access code, which cannot complete in a single call. The caller must run SendAccessCode, collect the code, then ValidateAccessCode.

Functions

func GenerateClearSaleSession

func GenerateClearSaleSession(doer store.HTTPDoer, endpoint string) (string, error)

GenerateClearSaleSession registers an anti-fraud device fingerprint and returns the session ID to send as deviceFingerprint on a card payment.

Nothing here is store-specific — the app key and SDK identifiers are common to the VTEX/ClearSale integration — so it lives in the library and is reached only when a store sets the ClearSaleFingerprint quirk.

doer and endpoint are injected: the original implementation called the package-level http.Get, which bypassed the client's transport and had no timeout, so a hung ClearSale host stalled checkout indefinitely.

Types

type Client

type Client struct {

	// GatewayURL overrides the payment gateway host. Tests set it; empty
	// means the production vtexpayments host derived from the account.
	GatewayURL string
	// ClearSaleURL overrides the ClearSale fingerprint host for tests.
	ClearSaleURL string
	// SettlementInterval overrides the delay between order settlement
	// polls. Tests shorten it; zero means the default.
	SettlementInterval time.Duration
	// SubscriptionsURL overrides the Subscriptions (RNS) host. Tests set it;
	// empty means the account host from store.AccountBaseURL.
	SubscriptionsURL string
	// contains filtered or unexported fields
}

func New

func New(s store.Store, authToken string) *Client

func (*Client) AddToCart

func (c *Client) AddToCart(orderFormID, skuID, seller string, quantity int) (*OrderForm, error)

AddToCart adds a SKU. The seller comes from the caller — normally straight off a SearchResult — because it is not a store-wide constant.

func (*Client) AddToWishlist added in v0.4.0

func (c *Client) AddToWishlist(shopperID, listName string, item WishlistItem) error

AddToWishlist saves a product to the shopper's wishlist. productID and sku differ for products with variants and the API wants both.

func (*Client) AuthStart

func (c *Client) AuthStart() (*store.Capabilities, error)

AuthStart probes what login methods this store supports.

func (*Client) AuthToken

func (c *Client) AuthToken() string

func (*Client) AuthenticatedUser

func (c *Client) AuthenticatedUser() (string, error)

AuthenticatedUser returns the logged-in email, or an error when the stored token has expired.

func (*Client) AwaitOrderSettlement added in v0.4.3

func (c *Client) AwaitOrderSettlement(orderGroup string) (*OrderDetail, error)

AwaitOrderSettlement re-reads an order until the gateway has settled a payment on it, the store has cancelled it, or the poll budget runs out.

Running out is an answer, not an error: the caller gets the last state the store reported and must say so rather than claim a placed order. Only an order that could not be read at all is an error, because then there is nothing true to report.

func (*Client) ClassicLogin

func (c *Client) ClassicLogin(email, password string) (string, error)

ClassicLogin authenticates with email and password against stock VTEX ID.

func (*Client) GatewayCallback

func (c *Client) GatewayCallback(orderGroup string) error

GatewayCallback finalizes a card payment. The gateway answers 428 while the transaction is still settling, so this retries with a linear backoff.

func (*Client) Get

func (c *Client) Get(path string) ([]byte, error)

func (*Client) GetDeliveryWindows

func (c *Client) GetDeliveryWindows(orderFormID string) ([]DeliveryWindow, error)

GetDeliveryWindows lists the windows available for the cart's address. Requires an orderForm with a shipping address, so it needs authentication; use Simulate for an unauthenticated check.

Windows are deduplicated across items and reindexed from zero, because `--window N` indexes into the returned slice.

func (*Client) GetOrder

func (c *Client) GetOrder(orderID string) (*OrderDetail, error)

GetOrder reads one order.

Checkout reports the order *group*, which is the id a caller actually holds, while OMS keys orders as "<group>-<seq>". The id is tried exactly as given first, so a full order id behaves as it always has; the fallback only makes the id the CLI printed usable. A group id answers either 404 or a body with no order in it, and neither is an order.

func (*Client) GetOrderForm

func (c *Client) GetOrderForm(orderFormID string) (*OrderForm, error)

func (*Client) GetSavedCards

func (c *Client) GetSavedCards(orderFormID string) ([]SavedCard, error)

func (*Client) GetSession

func (c *Client) GetSession() (*Session, error)

GetSession reads the auth cookie, cart pointer, and logged-in email from the VTEX sessions API.

The auth cookie key is account-scoped (VtexIdclientAutCookie_frescatto), so the response cannot be unmarshalled through a fixed struct tag the way the pre-extraction implementations did. It is decoded into a map and looked up by the descriptor's cookie name.

func (*Client) GetSubscription added in v0.5.0

func (c *Client) GetSubscription(id string) (*Subscription, error)

func (*Client) HTTPClient

func (c *Client) HTTPClient() *http.Client

func (*Client) ListOrders

func (c *Client) ListOrders() ([]Order, error)

func (*Client) ListSubscriptions added in v0.5.0

func (c *Client) ListSubscriptions() ([]Subscription, error)

ListSubscriptions returns the shopper's subscriptions.

The endpoint takes a customerEmail filter, but a shopper token already scopes the result to its own customer — verified against a live account — so passing one would only cost an extra round trip to learn our own email.

func (*Client) Login

func (c *Client) Login(ctx context.Context, email, password string) (string, error)

Login authenticates with whichever strategy the store supports, preferring a registered OAuth driver, then classic email+password, then access key.

The strategy is discovered rather than declared: a store descriptor does not say how to log in, the storefront does.

func (*Client) NewOrderForm

func (c *Client) NewOrderForm() (*OrderForm, error)

NewOrderForm mints a genuinely new cart.

It must use its own cookie jar: VTEX pins a client to its current cart via a checkout cookie, so calling GET /orderForm on a client that has already touched a cart hands back that same cart. Without a clean jar this silently returns the cart you were trying to escape.

func (*Client) PatchJSON

func (c *Client) PatchJSON(path string, payload any) ([]byte, error)

func (*Client) PayWithSavedCard

func (c *Client) PayWithSavedCard(tx *TransactionResult, card SavedCard, cvv string, orderValue money.Centavos) error

PayWithSavedCard submits a card payment to the VTEX payment gateway.

ClearSale fingerprinting is applied only for stores carrying the ClearSaleFingerprint quirk. Zona Sul's gateway rejects card payments without it (Cielo code 59); Frescatto shows no sign of needing it.

func (*Client) PlaceOrder

func (c *Client) PlaceOrder(orderFormID string, orderValue money.Centavos) (*TransactionResult, error)

PlaceOrder converts the cart into a transaction. This is the point of no return for non-card payments.

func (*Client) PostForm

func (c *Client) PostForm(path string, values url.Values) ([]byte, error)

PostForm submits form-encoded values. VTEX ID's validate endpoints reject JSON bodies, so auth uses this rather than PostJSON.

func (*Client) PostJSON

func (c *Client) PostJSON(path string, payload any) ([]byte, error)

func (*Client) PostJSONAbsolute

func (c *Client) PostJSONAbsolute(absoluteURL string, payload any) ([]byte, error)

PostJSONAbsolute posts to a full URL rather than a storefront path. The payment gateway lives on a different host, so it cannot use PostJSON.

func (*Client) RefreshToken

func (c *Client) RefreshToken() (string, error)

RefreshToken asks the sessions API for a fresher JWT. It returns an empty string when the session carries no token, which means the caller must re-authenticate rather than treat it as an error.

func (*Client) RemoveAllItems

func (c *Client) RemoveAllItems(orderFormID string) error

func (*Client) RemoveFromWishlist added in v0.4.0

func (c *Client) RemoveFromWishlist(shopperID, listName string, id int) (bool, error)

RemoveFromWishlist deletes an item by its wishlist ID, which is not the SKU. Callers resolve a SKU to an ID by reading the list first.

func (*Client) ResolvePaymentSystem

func (c *Client) ResolvePaymentSystem(of *OrderForm, name string) (int, error)

ResolvePaymentSystem maps a human name such as "pix" to the store's own payment system ID, discovered from the order form. IDs are not portable between stores, so this replaces the hardcoded map the CLIs used to carry.

func (*Client) Search

func (c *Client) Search(query string, limit int) ([]SearchResult, error)

Search queries the store catalog using the descriptor's configured mode.

SearchAuto tries Intelligent Search REST first and falls back to the catalog REST API. Neither needs a persisted GraphQL hash, which is what made the previous implementation brittle: VTEX rotates that hash on every search-graphql release and a stale one returns no results.

func (*Client) SendAccessCode

func (c *Client) SendAccessCode(email string) error

SendAccessCode emails a one-time login code and records the pending authentication token, which the subsequent validate call must reuse.

func (*Client) SetAddress

func (c *Client) SetAddress(orderFormID string, numItems int) error

SetAddress applies the account's saved delivery address to the cart.

func (*Client) SetAuthToken

func (c *Client) SetAuthToken(token string)

func (*Client) SetPayment

func (c *Client) SetPayment(orderFormID string, paymentSystemID int, value money.Centavos) error

func (*Client) SetPaymentWithSavedCard

func (c *Client) SetPaymentWithSavedCard(orderFormID string, card SavedCard, value money.Centavos) error

func (*Client) SetShippingWindow

func (c *Client) SetShippingWindow(orderFormID string, window DeliveryWindow, numItems int) error

SetShippingWindow selects a delivery window for every item in the cart.

func (*Client) SetSubscriptionStatus added in v0.5.0

func (c *Client) SetSubscriptionStatus(id, status string) (*Subscription, error)

SetSubscriptionStatus moves a subscription between ACTIVE and PAUSED.

CANCELED is deliberately refused. RNS has no transition out of it, so a mistyped ID would destroy a subscription with no way back from this CLI.

func (*Client) Simulate

func (c *Client) Simulate(items []SimulationItemRequest, cep string) (*Simulation, error)

Simulate prices a basket against a postal code without authentication. This is how delivery windows and payment methods can be inspected before anyone logs in.

func (*Client) SkipSubscription added in v0.5.0

func (c *Client) SkipSubscription(id string, skip bool) (*Subscription, error)

SkipSubscription skips the next cycle, or restores it when skip is false.

func (*Client) Store

func (c *Client) Store() store.Store

func (*Client) UpdateItemQuantity

func (c *Client) UpdateItemQuantity(orderFormID string, index, quantity int) (*OrderForm, error)

UpdateItemQuantity sets an absolute quantity, not a delta. Setting 0 removes the item.

func (*Client) UsableCart

func (c *Client) UsableCart(persistedID string) (*OrderForm, bool, error)

UsableCart returns a cart that can actually complete a checkout.

VTEX snapshots account data into an order form at creation time and never refreshes it — refreshOutdatedData does not help. A cart minted before the account had a profile or address is therefore permanently unusable, and because the CLI persists a cart id across invocations, a user who tried the CLI before completing their profile would be stuck forever with no way out but deleting the config by hand.

When the persisted cart cannot check out, this mints a fresh one and carries the items across, so nothing the user added is lost.

func (*Client) ValidateAccessCode

func (c *Client) ValidateAccessCode(code, emailOverride string) (string, string, error)

ValidateAccessCode exchanges an emailed code for a JWT. It returns the token and the email it authenticated, then clears the pending record.

func (*Client) Wishlists added in v0.2.0

func (c *Client) Wishlists(shopperID string) ([]Wishlist, error)

Wishlists returns the shopper's server-side wishlists — the same lists the storefront's heart icons write to.

type DeliveryWindow

type DeliveryWindow struct {
	Index    int            `json:"index"`
	Start    time.Time      `json:"start"`
	End      time.Time      `json:"end"`
	Price    money.Centavos `json:"price"`
	LisPrice money.Centavos `json:"lisPrice"`
	Tax      money.Centavos `json:"tax"`
	// RawStart and RawEnd preserve the exact strings VTEX sent. The
	// shipping-window request must echo them back byte for byte; a
	// re-formatted timestamp is rejected.
	RawStart string `json:"-"`
	RawEnd   string `json:"-"`
}

type Frequency added in v0.5.0

type Frequency struct {
	Periodicity string `json:"periodicity"`
	Interval    int    `json:"interval"`
}

Frequency is how often a subscription reorders: interval 2 with periodicity WEEKLY means every two weeks.

func (Frequency) String added in v0.5.0

func (f Frequency) String() string

String renders the frequency the way a shopper reads it.

type Order

type Order struct {
	OrderID           string         `json:"orderId"`
	CreationDate      string         `json:"creationDate"`
	Status            string         `json:"status"`
	StatusDescription string         `json:"statusDescription"`
	TotalValue        money.Centavos `json:"totalValue"`
	TotalItems        int            `json:"totalItems"`
}

type OrderDetail

type OrderDetail struct {
	OrderID           string         `json:"orderId"`
	Status            string         `json:"status"`
	StatusDescription string         `json:"statusDescription,omitempty"`
	CreationDate      string         `json:"creationDate,omitempty"`
	AuthorizedDate    string         `json:"authorizedDate,omitempty"`
	Value             money.Centavos `json:"value"`
	Authorized        bool           `json:"authorized"`
	TID               string         `json:"tid,omitempty"`
	Payments          []OrderPayment `json:"payments,omitempty"`
	Items             []OrderItem    `json:"items"`
}

OrderDetail is one order as the store reports it after the fact.

Authorized and TID are derived at parse time because they answer the only question worth asking once an order exists: did money actually move. On 2026-08-18 a Frescatto order printed as placed while every payment on it carried a null tid and an empty connector response; the gateway cancelled it five minutes later.

func (*OrderDetail) Canceled added in v0.4.3

func (o *OrderDetail) Canceled() bool

Canceled reports whether the store has cancelled this order or started to. Every VTEX cancellation status carries the word.

type OrderForm

type OrderForm struct {
	OrderFormID    string          `json:"orderFormId"`
	Items          []OrderFormItem `json:"items"`
	Totalizers     []Totalizer     `json:"totalizers"`
	PaymentSystems []PaymentSystem `json:"-"`
	Value          money.Centavos  `json:"value"`
	LoggedIn       bool            `json:"loggedIn"`
	// AddressCount is how many delivery addresses this cart can see. VTEX
	// snapshots account data into an order form when it is created, so a
	// cart minted before the account had an address reports zero here
	// forever — it can never complete a checkout.
	AddressCount int `json:"addressCount"`
}

func (*OrderForm) Checkoutable

func (o *OrderForm) Checkoutable() bool

Checkoutable reports whether this cart can reach a completed order. A cart with no visible address cannot, regardless of what the account has.

func (*OrderForm) ItemsTotal

func (o *OrderForm) ItemsTotal() money.Centavos

ItemsTotal returns the Items totalizer, which excludes shipping. Checkout minimums are assessed against this, not the order total.

func (*OrderForm) Total

func (o *OrderForm) Total() money.Centavos

Total sums every totalizer: items, discounts, and shipping.

type OrderFormItem

type OrderFormItem struct {
	ID           string         `json:"id"`
	ProductID    string         `json:"productId"`
	Name         string         `json:"name"`
	Quantity     int            `json:"quantity"`
	Price        money.Centavos `json:"price"`
	SellingPrice money.Centavos `json:"sellingPrice"`
	Seller       string         `json:"seller"`
	Unit         string         `json:"measurementUnit"`
	UnitMult     float64        `json:"unitMultiplier"`
}

type OrderItem

type OrderItem struct {
	ID       string         `json:"id"`
	SKU      string         `json:"sellerSku"`
	Name     string         `json:"name"`
	Quantity int            `json:"quantity"`
	Price    money.Centavos `json:"price"`
}

type OrderPayment added in v0.4.3

type OrderPayment struct {
	ID                 string         `json:"id"`
	PaymentSystemName  string         `json:"paymentSystemName"`
	Group              string         `json:"group"`
	Value              money.Centavos `json:"value"`
	TID                string         `json:"tid"`
	ConnectorResponses map[string]any `json:"connectorResponses,omitempty"`
}

OrderPayment is one payment on a placed order, as the store reports it afterwards. Card and account identifiers are deliberately not modeled: nothing this CLI does needs them, and what is not parsed cannot leak.

type PaymentSystem

type PaymentSystem struct {
	ID        int    `json:"id"`
	Name      string `json:"name"`
	GroupName string `json:"groupName"`
}

PaymentSystem is one payment method the store accepts. Discovered from the orderForm rather than hardcoded, because the set differs per store.

type PendingAuth

type PendingAuth struct {
	Email               string `json:"email"`
	AuthenticationToken string `json:"authenticationToken"`
}

PendingAuth records an in-flight access-code login. VTEX rejects a validate call whose authenticationToken came from a different start call, so the token has to survive between the two CLI invocations.

type SavedCard

type SavedCard struct {
	AccountID         string `json:"accountId"`
	CardNumber        string `json:"cardNumber"`
	Bin               string `json:"bin"`
	PaymentSystem     string `json:"paymentSystem"`
	PaymentSystemName string `json:"paymentSystemName"`
}

type SearchResult

type SearchResult struct {
	ProductID string         `json:"productId"`
	SKU       string         `json:"sku"`
	Name      string         `json:"name"`
	Price     money.Centavos `json:"price"`
	ListPrice money.Centavos `json:"listPrice"`
	Available int            `json:"available"`
	Seller    string         `json:"seller"`
	Unit      string         `json:"unit"`
	UnitMult  float64        `json:"unitMultiplier"`
}

SearchResult is one purchasable SKU.

Seller is carried per result rather than assumed from a constant: it is the value the cart API needs, and it differs per store (and in principle per item within a store).

type Session

type Session struct {
	AuthToken   string `json:"authToken"`
	OrderFormID string `json:"orderFormId"`
	Email       string `json:"email"`
}

Session is the storefront's view of the current visitor.

type Simulation

type Simulation struct {
	Items          []SimulationItem          `json:"items"`
	LogisticsInfo  []SimulationLogisticsInfo `json:"logisticsInfo"`
	PaymentSystems []PaymentSystem           `json:"paymentSystems"`
}

type SimulationItem

type SimulationItem struct {
	ID       string         `json:"id"`
	Quantity int            `json:"quantity"`
	Price    money.Centavos `json:"price"`
}

type SimulationItemRequest

type SimulationItemRequest struct {
	ID       string `json:"id"`
	Quantity int    `json:"quantity"`
	Seller   string `json:"seller"`
}

type SimulationLogisticsInfo

type SimulationLogisticsInfo struct {
	SLAs []SimulationSLA `json:"slas"`
}

type SimulationSLA

type SimulationSLA struct {
	Name                     string           `json:"name"`
	Price                    money.Centavos   `json:"price"`
	ShippingEstimate         string           `json:"shippingEstimate"`
	AvailableDeliveryWindows []DeliveryWindow `json:"availableDeliveryWindows"`
}

type Subscription added in v0.5.0

type Subscription struct {
	ID               string               `json:"id"`
	CustomerEmail    string               `json:"customerEmail"`
	Title            string               `json:"title"`
	Status           string               `json:"status"`
	IsSkipped        bool                 `json:"isSkipped"`
	NextPurchaseDate string               `json:"nextPurchaseDate"`
	LastPurchaseDate string               `json:"lastPurchaseDate"`
	CycleCount       int                  `json:"cycleCount"`
	Plan             SubscriptionPlan     `json:"plan"`
	Settings         SubscriptionSettings `json:"purchaseSettings"`
	Items            []SubscriptionItem   `json:"items"`
}

Subscription is one recurring order.

The address and payment method RNS reports are opaque VTEX IDs with nothing a shopper could read, so they are not surfaced. DeliveryWindow is the one human-readable part of purchaseSettings — Mantiqueira returns "Receba às terças-feiras".

type SubscriptionItem added in v0.5.0

type SubscriptionItem struct {
	ID        string         `json:"id"`
	SKU       string         `json:"skuId"`
	Quantity  int            `json:"quantity"`
	Status    string         `json:"status"`
	IsSkipped bool           `json:"isSkipped"`
	Price     money.Centavos `json:"priceAtSubscriptionDate"`
}

SubscriptionItem is one SKU in a subscription. A subscription can carry several, and each can be skipped independently of the subscription itself.

Price is the price locked in when the subscription was created, which is why it keeps the API's name rather than becoming a plain "price" — it is not today's shelf price. RNS sends it as integer centavos serialized as a float (6590.0 for R$65,90), the same encoding the OMS uses, so money.Centavos reads it correctly with no conversion.

type SubscriptionPlan added in v0.5.0

type SubscriptionPlan struct {
	ID        string    `json:"id"`
	Frequency Frequency `json:"frequency"`
}

type SubscriptionSettings added in v0.5.0

type SubscriptionSettings struct {
	DeliveryWindow string `json:"selectedSla"`
}

SubscriptionSettings carries the only human-readable part of the API's purchaseSettings; the rest is payment and address IDs.

type Totalizer

type Totalizer struct {
	ID    string         `json:"id"`
	Name  string         `json:"name"`
	Value money.Centavos `json:"value"`
}

type TransactionResult

type TransactionResult struct {
	OrderGroup    string `json:"orderGroup"`
	TransactionID string `json:"transactionId"`
	ReceiverURI   string `json:"receiverUri"`
	MerchantName  string `json:"merchantName"`
}

type Wishlist added in v0.2.0

type Wishlist struct {
	Name   string         `json:"name"`
	Public bool           `json:"public"`
	Items  []WishlistItem `json:"items"`
}

type WishlistItem added in v0.2.0

type WishlistItem struct {
	ID        int    `json:"id"`
	ProductID string `json:"productId"`
	SKU       string `json:"sku"`
	Title     string `json:"title"`
}

WishlistItem is one saved product from the store's own wishlist.

ID is the item's position-derived identifier within the list, and it is what RemoveFromList takes — not the SKU. ProductID and SKU genuinely differ for products with variants, and AddToList wants both.

Jump to

Keyboard shortcuts

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