Skip to main content
@chipi-stack/chipi-react exposes the read side of the Bills flow as React Query hooks (useGetSkuList, useGetSku, useGetSkuPurchase). The purchase itself is a plain useMutation calling POST /v1/sku-purchases — the SDK’s usePurchaseSku hook wraps an on-chain wallet path that’s reserved for Chipi’s internal PWA, not what you want here.
Every endpoint on this page is guarded by Chipi’s BearerTokenGuard and requires both an x-api-key header and a customer JWT in the Authorization: Bearer header. The JWT is issued by your auth provider (Clerk, Auth0, BetterAuth, your own); Chipi validates it against the JWKS URL you register for this API key.

Install

Wrap your app in ChipiProvider

ChipiProvider accepts your ChipiSDKConfig. It mounts a built-in QueryClient, so you don’t need to provide one separately for Chipi hooks.

Resolve a customer JWT

Every hook + the purchase mutation need a customer JWT. Wrap your auth-provider’s session-token getter in a getBearerToken function. With Clerk:
The same pattern works with Auth0 (getAccessTokenSilently), BetterAuth (session.token), or any provider that exposes a signed session token. The token is sent verbatim in the Authorization: Bearer header and validated against your registered JWKS URL.

Browse the catalog — useGetSkuList

Filters are typed in @chipi-stack/types@14.4.0: provider ("TET" | "CHIPI"), category (SkuCategory enum), chipiCategory (curated taxonomy code), carrierName (case-insensitive substring).
The hook is automatically disabled until getBearerToken returns a non-null token, so it’s safe to render before sign-in. data shape: PaginatedResponse<Sku>{ data: Sku[], total, page, limit, totalPages }.

Look up a single SKU — useGetSku

Submit a purchase — custom useMutation against /v1/sku-purchases

Use React Query’s useMutation to wrap a plain fetch. The request body matches the CreateSkuPurchaseInput DTO on chipi-back. transactionHash is purely an idempotency key — any unique string is fine; re-sending the same value within the day returns the existing Transaction row instead of double-charging.
The mutation returns a Transaction. id is what you pass to useGetSkuPurchase to poll for settlement.

Poll for settlement — useGetSkuPurchase

For production traffic, prefer a webhook over polling — configure one at /configure/notifications in the dashboard.

DEV sandbox

When NEXT_PUBLIC_CHIPI_PUBLIC_KEY is a DEV key (pk_dev_...), every purchase is sandboxed:
  • No real credits debited. Your OrgBalance.availableUsd is never touched.
  • No carrier call. TET is never invoked.
  • Deterministic SUCCESS. Every purchase succeeds within milliseconds.
Sandbox responses are tagged so your UI can distinguish them — ledgerEntryId starts with le-dev- and skuFileNumber starts with dev-sandbox-. Swap to pk_prod_... (and point the catalog reads at the production data) and the same code path runs against the real carrier.

Putting it together

What’s next

  • Need server-side billing instead? See the Node guide — same REST pattern with fetch + customer JWT.
  • Need to filter by carrier? Use carrierName — case-insensitive substring match.
  • Need credits to actually charge for purchases? See Billing & Credits.
✅ Verified against the live API on 2026-05-19 — same REST contract used in the production smoke purchase against Legaria (transaction tx-75456794-f4b8-4835-8282-0f89f1964eda, sku-VIR020 Virgin $20 MXN, settled SUCCESS in < 5s).