Skip to main content
After OAuth, you can load every sale the current user can see and render them with the SDK - no hand-written HTTP integration for the common case.

Prerequisites

  • CoinListProvider with working getAccessToken (session established on your backend)
  • User signed in: your getAccessToken returns a non-null access token after OAuth (see Set up OAuth authentication)
OffersGridContainer uses useOffers internally and renders a responsive grid of offer cards with loading, error, and empty states.
Optional props:
  • maxColumns - upper bound for the grid when space allows (default 3)
  • loading, error, emptyState - replace default slots with your own React nodes
  • onOfferClick - when set, cards become interactive; omit for read-only lists
  • data - pre-fetched offers from CoinListServer’s coinlist.offers.list() for SSR. Pass them in to skip the client-side request on first render.
For full control over markup while keeping the SDK’s logic, call useOffersGridViewModel() yourself and render OffersGridView (or your own markup) against the state it returns.

Server-side pre-fetch

Every hook and container that fetches accepts data. Pass it and the component uses that data as-is and skips the initial client-side fetch - the user sees offers in the first paint instead of a spinner. This is the SSR path. Your Server Component calls CoinListServer, and the browser renders with the answer already in hand:
Use a read-only session store in Server Components: they can read cookies but not write them, so a writable store would silently consume a refresh token. See read-only session stores.
The same prop exists on the hooks (useOffers({ data })) and on the other data-backed containers, including RequirementsChecklistContainer. Where a hook exposes refetch(), the seed answers the initial render only - an explicit refetch still goes to the network. coinlist.offers.list() on the server also takes an optional app-level token from coinlist.auth.clientCredentials(), so a public catalogue page can render with no user session at all.

Going lower

Open these when you need custom layouts or non-React code.
Use useOffers from @coinlist-co/react when you want full control over markup but still prefer reactive loading state.The hook exposes offersState:
  • LOADING - provider not ready or request in flight
  • ERROR - reason is not-authenticated or generic-error
  • CONTENT - offers is every page of offers merged (same data as coinlist.offers.list())
Pass data if you have server-fetched offers to hydrate from: useOffers({ data }).
Inside React you usually reach these through useCoinList():
  • coinlist.offers.list() - iterates every paginated page and returns all offers (throws NotAuthenticatedError if the user is not logged in)
  • coinlist.offers.listPage(params) - one page of API results when you implement your own pagination UI
For imperative, non-hook usage, create a CoinListClient with createCoinListClient from @coinlist-co/react. Server code (Next.js Route Handlers, Server Components) should use the equivalent coinlist.offers.list() on CoinListServer from @coinlist-co/react/server instead - on the server it also takes an optional app-level token from coinlist.auth.clientCredentials(), so it can run with no user session.
The SDK calls the same API documented in the API reference. Use raw HTTP only if you are not using React, or you need fields or flows the SDK does not expose yet. You still need a valid Bearer access token from your OAuth session.

Token display metadata

Offers carry chain and address pairs in offer.tokens, but not the name, symbol, decimals or logo you need to render them. Those come from CoinList’s public token registry through coinlist.tokens.
A TokenMetadata carries identifier, name, symbol, decimals, logo and logoDark. logo is a union: VECTOR is a single SVG url, while RASTER carries an original plus webp variants at 32 to 512px - pick the smallest variant that covers your render size, or original if none does. coinlist.tokens is the one unauthenticated namespace: no method needs a logged-in user, and reads go to the registry’s CDN rather than the CoinList API. It works with no session at all, and with a read-only server session store.
  • coinlist.tokens.get(token) returns metadata for one token, or null when the registry does not list it. The registry is curated, so null is a normal answer: fall back to your own display defaults rather than treating it as an error.
  • coinlist.tokens.list(chain) returns every token the registry lists for a chain, in one request. Prefer it over calling get in a loop when rendering a catalogue - two hundred tokens is still a single snapshot download. A missing chain snapshot throws rather than returning [], because its absence is a deployment problem and not an empty catalogue.
useTokenMetadata takes enabled and data like the other data hooks, and exposes refetch(). A data of null is a valid seed meaning “not in the registry”, and is distinct from leaving data undefined.

Next step

Display offer details

Load the full OfferDetail for an id from the grid, which is what checkout takes.