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 the OAuth recipe)
OffersGrid uses useOffers internally and renders a responsive grid of offer cards with loading, error, and empty states.
"use client";

import { OffersGrid } from "@coinlist-co/react";

export function OffersSection() {
  return (
    <OffersGrid
      maxColumns={3}
      onOfferClick={(offer) => {
        // Navigate or open your detail route - offer.id is the API offer id
        console.log("Selected offer", offer.id);
      }}
    />
  );
}
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.fetchOffers() for SSR. Pass them in to skip the client-side request on first render.

Lower-level APIs

Open these sections 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 fetchOffers)
"use client";

import { useOffers } from "@coinlist-co/react";

export function CustomOffersLayout() {
  const { offersState } = useOffers();

  if (offersState.type === "LOADING") return <p>Loading…</p>;
  if (offersState.type === "ERROR") return <p>Could not load offers.</p>;

  return (
    <ul>
      {offersState.offers.map((offer) => (
        <li key={offer.id}>{offer.tagline ?? offer.slug}</li>
      ))}
    </ul>
  );
}
Pass data if you have server-fetched offers to hydrate from: useOffers({ data }).
Inside React you usually reach these through useCoinList():
  • coinlist.fetchOffers() - iterates every paginated page and returns all offers (throws NotAuthenticatedError if the user is not logged in)
  • coinlist.fetchOffersPage(params) - one page of API results when you implement your own pagination UI
"use client";

import { useCoinList } from "@coinlist-co/react";
import { useEffect } from "react";

export function OffersDebugLogger() {
  const { coinlist, isReady } = useCoinList();

  useEffect(() => {
    if (!isReady) return;
    void coinlist.fetchOffers().then((offers) => {
      console.log(offers.length);
    });
  }, [coinlist, isReady]);

  return null;
}
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 CoinListServer.fetchOffers() from @coinlist-co/react/server instead.
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.

Next step

Display offer details

Load full offer details for an id from the grid or fetchOffers.