Building UIs on the Fiber API
The pattern book for wrapping Fiber in your own web UI — autocomplete that resolves, live match counts, cursor-paginated tables, progress for slow jobs, and credits on screen. With toy Next.js examples.
Building UIs on the Fiber API
Everything the Fiber dashboard does runs on the same public API your key unlocks. We built the UI and the API on the same surface. A search-and-enrich interface of your own is therefore mostly composition: a handful of operations that map one-to-one onto UI elements, a server route that holds your key, and a way to surface results when the work is async. This page walks those patterns with toy examples, and OpenFiber is the same book at full scale.
Want a working app instead of a pattern book? We open-sourced one. OpenFiber is an MIT-licensed Next.js prospecting UI over ~180 operations — run it in five minutes, fork it, or strip it for parts.
What you're building
Six UI elements cover nearly every data surface on Fiber:
| UI element | Backed by | Watch out for |
|---|---|---|
| Filter autocomplete | Typeaheads: companyTypeahead, locationTypeahead, skillsTypeahead, jobTitleRewrite | All four share 240 requests/minute |
| Live match count | companyCount, peopleSearchCount, jobPostingSearchCount, combinedSearchCount | Estimates cap at 10,000 |
| Results table | companySearch, peopleSearch, paginatedCombinedSearch | Cursor-paginated; 1 credit per result |
| Reveal-contacts button | syncQuickContactReveal | Sync — returns inline |
| Bulk enrich with progress | startBatchContactDetails → pollBatchContactDetails | Async; 10–2,000 identifiers per job |
| Credits meter | getOrgCredits (free) + chargeInfo on every response | One entry per subscription |
The one architectural rule: the key stays on the server
The browser never talks to api.fiber.ai directly. Every call flows
browser → your server routes → Fiber, with the
API key read from the server environment. That keeps
the key out of client bundles and network tabs, and gives you one place to
add caching, per-user limits, or your own auth — which is also what makes a
Fiber-powered UI safe to put behind your own login.
A toy Next.js route handler that pages companies:
// app/api/companies/route.ts
import { companySearch } from "@fiberai/sdk";
import type { CompanySearchData } from "@fiberai/sdk";
export async function POST(req: Request) {
const { searchParams, cursor } = (await req.json()) as {
searchParams: CompanySearchData["body"]["searchParams"];
cursor?: string;
};
const result = await companySearch({
body: {
apiKey: process.env.FIBER_API_KEY!,
searchParams,
pageSize: 25,
cursor, // omit on the first page
},
});
if (result.error) {
return Response.json(result.error, {
status: result.response.status,
});
}
// output: { data, nextCursor, estimatedCount }
return Response.json(result.data.output);
}Every pattern below plugs into a route like this one. See SDKs for typed clients in TypeScript and Python.
Autocomplete resolves; free text guesses
Search filters expect canonical values, and the typeaheads return exactly
those: companies (plus schools and investors via orgType), locations with
coordinates and metro-region presets, professional skills, and job-title
synonym families. Picking from the list is a deterministic match; typing
"MIT" into an education filter is a gamble.
A toy debounced autocomplete:
const [suggestions, setSuggestions] = useState([]);
const [query, setQuery] = useState("");
useEffect(() => {
if (query.length < 3) return; // don't fire on every keystroke
const timer = setTimeout(async () => {
const res = await fetch("/api/typeahead/company", {
method: "POST",
body: JSON.stringify({ startsWith: query }),
});
setSuggestions(await res.json());
}, 300); // debounce behind a pause
return () => clearTimeout(timer);
}, [query]);Store what the user picked (the entity's slug, domain, or coordinates), not the string they typed. Skills typeahead is free at any frequency; the other three cost a credit per call, and all four share one 240 requests/minute budget, so debounce everything. Full behavior per endpoint: Typeaheads.
Match counts live in the filter UI
Count endpoints answer "how many match?" without pulling a single record.
They return { output: { count } }, small enough to refresh on every filter
change. Show the number next to the Search button
("1,240 companies match") and users tune filters against feedback instead of
guessing, then commit once.
Counts are estimates capped at 10,000 — display "10,000+" at the cap, not a fake total. A capped count means "keep narrowing", not "exactly 10,000". Pricing detail: count before you spend.
Results tables page with cursors
Ask for up to 1,000 results per page (pageSize, default 25); the
response carries a nextCursor you pass back as cursor for the next
page. A "Load more" button is just nextCursor !== null.
Two rules worth encoding in your table component:
- A cursor belongs to one query. When the user changes filters, drop the cursor and start a fresh run — a recycled cursor quietly keeps serving the old query.
- Set an explicit
sortwhenever you're showing a sample of a large set. Filter-only results have no inherent ranking, so a defined sort is the difference between a reproducible sample and an accidental one.
Slow jobs get progress, not spinners
Batch reveal, exhaustive enrichment, and Maps sweeps run in the background for anywhere from seconds to minutes. The UI pattern:
- Commit. The user picks rows; you start a batch job with 10–2,000 identifiers and store the returned job identifier.
- Show per-row state. Poll that job every few seconds and render each row as pending, done, or failed — results land as they finish instead of blocking the table.
- Or skip the polling. Subscribe to
batch_contact_enrich.completedwith a webhook, verify the signature, update your store, and let the UI react. Ack fast and process async — retries are built in, and deduping on thesvix-idheader keeps replays harmless.
Tier-by-tier sync/async behavior, including the instant single-profile button: Contact Reveal.
Make cost a first-class citizen
Two fields, no bookkeeping required:
chargeInfoon every response is what that call actually cost. Show it where results appear ("this page: 25 credits"). It is authoritative over any published rate.- The balance read is free and returns
availableper subscription. Render a credits meter and refresh it after chargeable actions.
The error states a production UI should handle explicitly:
| Status | Meaning | UI response |
|---|---|---|
| 402 | Org out of credits | Pause jobs, link the purchase URL from the response |
| 429 | Rate limit hit | Back off and retry silently — users shouldn't see it |
| 403 | Key invalid or over its ceiling | Surface once, stop retrying |
| 400 | Malformed request | A bug in your payload — log it, don't retry |
Full error table and per-key spending ceilings: SDKs and API keys.
Start from the demo instead
Every pattern above is already assembled in OpenFiber — typeahead-driven filters with live match counts, cursor-paginated tables, batch jobs with progress, a credits meter — over ~180 operations, MIT-licensed:
git clone https://github.com/fiber-ai/open-fiber.git
cd open-fiber/nextjs
cp .env.example .env # set FIBER_API_KEY
npm install
npm run devAdding a feature is a four-step seam (page, server router wrapping the SDK operation, registration, nav entry), and a rebrand touches about five files. The details: OpenFiber.
Use cases
- Internal prospecting tool. Company filters with live counts, people search behind the same panel, batch reveal with per-row progress — the six elements above, wired end to end.
- Enrichment panel in your CRM. A reveal button per record, batch for CSV imports, the credits meter in the corner of the settings page.
- Market-sizing widget. Count endpoints only: "how many Series A fintechs in Germany" answers without spending search credits.
Credits
There is no UI-specific pricing. A call from your UI bills exactly like the
same call from anywhere else, and chargeInfo on each response stays
authoritative. See Billing & credits.
Related: OpenFiber · SDKs · Search · Typeaheads · Contact Reveal · Webhooks
Developing with AI Agents
Wire Fiber AI into Claude Code, Cursor, Codex, OpenCode, and 40+ other agents — plugins, MCP servers, and skills that search and enrich for you.
OpenFiber
An MIT-licensed, open-source prospecting UI built on the Fiber API — run it as-is, white-label it into your product, or fork it into something new.