This is a recipe, not a concept piece: every step is a tool call or a query
your agent can run as written. The task — the most common fusion there is:
you have crm.csv with a website column, and you want firmographics and
traffic per customer.
Step 1 — find data that joins with what you have (free)
Your join handle is a company domain. Search by it:
search_marketplace(joinable_on="domain", type="dataset")
search_marketplace(joinable_on="domain", type="api")
joinable_on returns only listings whose join card
declares a matching handle — each result carries the card, the schema, the
price, and a free sample. Suppose it finds a firmographics dataset
(table-to-table join) and a traffic API (lookup enrichment).
Step 2 — read the cards, plan the merge (free)
get_endpoint_sample("acme", "firmographics")
The card tells you what one row is (“one company”), the exact key format
(“domain, lowercase, no www”), and the grain. That format note is your
normalization spec — you now know precisely what to do to your website
column before you’ve spent anything.
Step 3 — set the guardrails, then buy
set_buy_policy(max_per_call_usd=0.50)
call_endpoint("acme", "firmographics", confirmed=true)
A dataset purchase returns a download URL plus a one-time pickup key; fetch it and the file streams to disk (a failed download re-streams against the same receipt — you don’t pay twice). Typical dataset prices on the marketplace today are cents, with an on-chain receipt per purchase.
Step 4 — normalize exactly as the card says, then join
-- DuckDB
CREATE TABLE crm AS SELECT *,
regexp_replace(lower(website),
'^https?://(www\.)?([^/]+).*', '\2') AS domain
FROM read_csv('crm.csv');
CREATE TABLE enriched AS
SELECT crm.*, f.hq_country, f.revenue_usd
FROM crm
LEFT JOIN read_parquet('firmographics.parquet') f
USING (domain);
Step 5 — measure before you trust
SELECT count(f.domain) * 1.0 / count(*) AS match_rate
FROM crm
LEFT JOIN read_parquet('firmographics.parquet') f
USING (domain);
A join card declares intent, not overlap — the match rate is the number
that tells you what you actually bought. Good result? Proceed. Poor result?
You’ve lost cents, not a license fee, and a zero-result joinable_on search
is worth posting as an ask so a vendor builds the bridge.
Step 6 — enrich the matches via the lookup API
# once per distinct matched domain
call_endpoint("acme", "traffic-by-domain",
params={"domain": d}, confirmed=true)
Lookup listings declare accepts/returns on their card — this one accepts
a domain and returns traffic stats, so each call appends columns to a row you
already hold. Your buy policy caps the per-call price; a
buy job caps the loop’s total.
The bill
For a 1,000-row CRM: one dataset download (cents) + one API call per matched domain at listing price. The entire plan was known — sources, keys, normalization, caps — before the first cent moved. That’s the point.
Guides: data fusion · buying with the connector