Developers

List your product from the terminal, a script, or your AI agent.

Reading the directory is free and needs no key. Creating and managing your own free listings needs an account, which is just an email address and a one-time code. One API key works everywhere: the CLI, the REST API and the MCP server.

Quick start

Three commands from nothing to a listing awaiting review.

npx @profullstack/saasrow login
# → enter your email, then the code we send you

saasrow listings create \
  --name "Acme Analytics" \
  --website https://acme.example \
  --description "Privacy-first product analytics you can self-host." \
  --category Analytics \
  --tags analytics,privacy,self-hosted \
  --pricing-model freemium

saasrow listings list

A listing submitted this way is exactly what the website's submit form produces: it is reviewed before it appears, it is free, and it gets the same management page and dofollow link.

CLI

A zero-dependency Node command, published as @profullstack/saasrow. Install it globally or run it with npx.

npm install -g @profullstack/saasrow

saasrow login                      # emailed code → API key stored locally
saasrow whoami
saasrow logout --revoke            # forget the key and kill it on the server

saasrow listings list
saasrow listings get <id>
saasrow listings create --name … --website … --description … [--tags a,b] [--use-cases …]
saasrow listings update <id> --description "…"
saasrow listings delete <id>

saasrow keys list
saasrow keys create "CI deploy"    # prints the key once
saasrow keys rename <id|prefix> "Laptop"
saasrow keys revoke <id|prefix>

saasrow search "analytics" --pricing-model free
saasrow categories
saasrow vocabulary

Every command accepts --json and then prints the raw API response, so output pipes cleanly into scripts and agents. For CI, skip the stored key and set SAASROW_API_KEY. Fields can also come from a file with --from listing.json.

Source and README: github.com/profullstack/saasrow-web/cli · npm: @profullstack/saasrow

MCP server

AI agents reach the directory over the Model Context Protocol. Without a key they can search; with one they can list your product for you.

# read-only
claude mcp add --transport http saasrow https://www.saasrow.com/api/mcp

# with an API key: your agent can create and manage your listings
claude mcp add --transport http saasrow https://www.saasrow.com/api/mcp \
  --header "Authorization: Bearer sr_…"

Or in any MCP client config:

{
  "mcpServers": {
    "saasrow": {
      "type": "http",
      "url": "https://www.saasrow.com/api/mcp",
      "headers": { "Authorization": "Bearer sr_…" }
    }
  }
}
readsearch_productsFilter by text, category, use case, audience, platform, pricing model, or alternative-to.
readget_productOne product by id.
readlist_categoriesEvery category with counts.
readget_vocabularyThe controlled filter terms.
writecreate_listingSubmit a free listing for review.
writelist_my_listingsEverything your account owns, any status.
writeget_my_listingOne of yours, any status.
writeupdate_listingChange any subset of fields.
writedelete_listingPermanent.

The server is stateless streamable HTTP. Details at /api/mcp.

REST API

Reads need nothing. Writes send an API key as a bearer token. Everything is JSON and CORS-enabled.

GET/api/v1/productsSearch and filter approved products. No key.
GET/api/v1/products/{id}One product with its JSON-LD. No key.
GET/api/v1/categories · /vocabulary · /statsDiscovery endpoints. No key.
GET/api/v1/meThe account behind your key.
GET POST/api/v1/listingsYour listings, any status; submit a new one.
GET PATCH DELETE/api/v1/listings/{id}One of yours.
GET POST/api/v1/keysList keys (prefix only); create one, returned once.
PATCH DELETE/api/v1/keys/{id}Rename; revoke.
POST/api/v1/auth/cli{ email } → we email a code.
POST/api/v1/auth/cli/verify{ email, code, key_name } → a new API key.
curl -X POST https://www.saasrow.com/api/v1/listings \
  -H "Authorization: Bearer sr_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Analytics",
    "website": "https://acme.example",
    "description": "Privacy-first product analytics you can self-host.",
    "category": "Analytics",
    "tags": ["analytics", "privacy"],
    "use_cases": ["analytics"],
    "pricing_model": "freemium",
    "alternatives": ["Google Analytics", "Mixpanel"]
  }'

Listing fields: name, website and description are required on create; category, tags, use_cases, audiences, platforms, pricing_model and alternatives are optional. Vocabulary terms outside the closed lists are dropped, never rejected. A website that is already listed returns 409. Errors come back as { "error": { "status", "message" } }.

The full, self-describing index lives at /api/v1.

API keys

Make as many as you have machines and agents. Name them, see when each was last used, revoke one without touching the others.

  • From the CLI: saasrow keys create "name". The first key comes from saasrow login.
  • From the website: the API keys panel on your listing management page (the link we email you).
  • From the API: POST /api/v1/keys with a key you already have.

A key looks like sr_ followed by 40 characters. We store only a hash, so the full key is shown exactly once, at creation. A key can do everything your management page can for your listings: treat it like a password, and revoke it the moment you suspect it leaked.

Accounts

No passwords. Proving you can read an inbox is the account.

saasrow login asks for an email, we send a one-time code (it expires in 15 minutes and works once), and the code becomes your first API key. The same email owns every listing ever submitted with it, including ones made on the website, so saasrow listings list shows all of them.

Listings created through the API are free, reviewed like any other submission, and renewable from the management page. Upgrading to a featured tier still happens on the pricing page.

Also for machines