ExShopifyApp.AppEvents (ex_shopify_app v1.2.0)
Client for the Shopify App Events API, used to report usage events.
Shopify maps each reported event to the meter configured on the app's pricing
plans, keyed by event_handle (which must match a meter handle exactly). Some
meters drive billing and others are tracking-only; this client is agnostic to that
distinction — the host app decides which meter does what, and owns the
idempotency-key strategy.
Authentication uses the app's Dev Dashboard credentials
(ExShopifyApp.api_key/0 / ExShopifyApp.api_secret/0) via the
client_credentials grant — see fetch_token/0 for the raw request. The resulting
JWT is valid ~60 min and cached by the configured ExShopifyApp.AppEvents.TokenCache
implementation (default ExShopifyApp.AppEvents.TokenServer) until shortly before it
expires.
Summary
Functions
Fetches a fresh App Events access token via the client_credentials grant.
Reports a usage event to Shopify.
Functions
@spec fetch_token() :: {:ok, String.t(), non_neg_integer()} | {:error, any()}
Fetches a fresh App Events access token via the client_credentials grant.
This is the raw primitive: it performs the token request and returns
{:ok, token, expires_in_seconds}, where expires_in_seconds is derived from the
JWT's exp claim (the endpoint returns only the token, not an expires_in field).
Returns {:error, %Tesla.Env{}} on a non-200 (or a 200 without a decodable token), or
{:error, reason} on a transport error. It does no caching — for cached access use the
configured ExShopifyApp.AppEvents.TokenCache (default
ExShopifyApp.AppEvents.TokenServer), which wraps this.
@spec report(ExShopifyApp.AppEvents.Event.t(), ExShopifyApp.Shop.identified()) :: {:ok, :accepted} | {:error, any()}
Reports a usage event to Shopify.
event is an ExShopifyApp.AppEvents.Event — see that struct for field
semantics, in particular the idempotency-key contract. shop is any map
carrying the shop's :shop_gid (see ExShopifyApp.Shop.identified/0 and
ExShopifyApp.Graphql.ensure_gid/2). The event comes first so builders pipe in:
Event.new(%{event_handle: "orders_processed", value: 1, idempotency_key: order_gid})
|> AppEvents.report(shop)The API acknowledges receipt with 202 regardless of billing validation.
Returns {:ok, :accepted} on 202, {:error, %Tesla.Env{}} on any other response,
or {:error, reason} on a transport error.