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_…" }
}
}
}| read | search_products | Filter by text, category, use case, audience, platform, pricing model, or alternative-to. |
| read | get_product | One product by id. |
| read | list_categories | Every category with counts. |
| read | get_vocabulary | The controlled filter terms. |
| write | create_listing | Submit a free listing for review. |
| write | list_my_listings | Everything your account owns, any status. |
| write | get_my_listing | One of yours, any status. |
| write | update_listing | Change any subset of fields. |
| write | delete_listing | Permanent. |
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/products | Search and filter approved products. No key. |
| GET | /api/v1/products/{id} | One product with its JSON-LD. No key. |
| GET | /api/v1/categories · /vocabulary · /stats | Discovery endpoints. No key. |
| GET | /api/v1/me | The account behind your key. |
| GET POST | /api/v1/listings | Your listings, any status; submit a new one. |
| GET PATCH DELETE | /api/v1/listings/{id} | One of yours. |
| GET POST | /api/v1/keys | List 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
- /llms.txt and /llms-full.txt — the directory as markdown for AI assistants
- /distribution — every channel a listing is published to, with measured stats
- /api/v1/stats — the counting method behind the numbers
