Export a market
Turn a saved market into rows: one page, then every page, then the same market as a spreadsheet.
A market is a ranked list of Swiss companies worth selling to, built from a definition you wrote in the app. This page takes one out as data, from the first page to the last, in the two formats the feed answers in.
Open the market and go to its Connect page. It carries a JSON URL, a CSV URL and the button that rotates the token in both.
Which companies you get
A market sorts its companies into two buckets. Core is the market's answer to who to sell to, and it is what the feed serves by default. Explore is the wider set the market found and has not committed to, which is where you look when Core is smaller than your team can work through.
# Core, the default
curl -s 'https://prospex.ch/app/markets/feed/<token>.json?limit=200'
# The wider bucket
curl -s 'https://prospex.ch/app/markets/feed/<token>.json?tab=explore&limit=200'
Both buckets carry the same fields, and bucket on each row says which one it came from.
Walking every page
The envelope carries next_url, absolute and complete. Following it until it is empty is the entire pagination protocol:
#!/usr/bin/env bash
set -euo pipefail
url="https://prospex.ch/app/markets/feed/${PROSPEX_MARKET_TOKEN}.json?limit=200"
: > market.jsonl
while [ -n "$url" ]; do
body=$(curl -sS --fail-with-body "$url") || {
echo "$body" | jq -r '"refused: \(.error) \(.message)"' >&2
exit 1
}
echo "$body" | jq -c '.data[]' >> market.jsonl
echo "$body" | jq -r '"\(.count) of \(.total), \(.usage.rows_today) rows today"' >&2
url=$(echo "$body" | jq -r '.next_url')
done
wc -l market.jsonl
Three things to note:
- It never builds a cursor. Cursors belong to the build that issued them; a hand-built one returns 400.
- It reads
.errorfrom the body of a refusal. Every refusal answers JSON, including the 402 and the 429. - It watches
usage.rows_today. A large market walked twice in a day can reach the row budget mid-walk.
When the market refreshes underneath you
Markets rebuild on a weekly schedule, and a rebuild can reorder the ranking. A cursor issued before it answers:
{
"error": "invalid_parameter",
"message": "This market has been refreshed since that cursor was issued, so its order has changed. Start again without a cursor."
}
Handle it by restarting the walk from the first page. market.refreshed_at in the envelope tells you which build you are reading.
The same market as a spreadsheet
The CSV needs no loop. It streams the whole bucket in one response, up to 10,000 rows, with human column headers instead of JSON keys:
curl -sS -o market.csv \
'https://prospex.ch/app/markets/feed/<token>.csv?tab=core'
Lists flatten rather than nest, because a CSV cell has nowhere to put an array: Reasons joins with a pipe, Missing with a comma, and the signal columns carry titles and ids for the same few recent events. When you need the structure, read the JSON. The market feed lists every column and the key behind it.
The four fields to map first
A market row carries the registry facts you would expect. These are the ones that carry the market's own judgement:
| Field | Use it for |
|---|---|
| fit | Sorting and filtering. It is the stored word, so it survives a change of interface language; fit_label is the version to show a person. |
| reasons | The first line of an opener, and the answer to "why is this company on my list". Same words the workspace shows. |
| missing | Deciding what to enrich yourself. An empty field means Prospex does not hold the data. |
| in_crm | Skipping companies your CRM already holds, if you connected one. |