API Reference

JSON REST API. All responses use a standard envelope. Rate limited per tier.

Base URL: https://saaspricingarchive.com/v1

How we collect this data, and how to request removal

Authentication

Get your API key at /signup. Include it in every request as a Bearer token.

curl https://saaspricingarchive.com/v1/account \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"
Your key is shown once at signup and sent to your email. To rotate it, call POST /v1/account/keys. The old key is immediately invalidated.

Response format

Every response wraps data in a standard envelope.

Success (2xx)

{
  "data": {'{ ... }'},
  "meta": {
    "request_id": "req_7x2k9m",
    "timestamp": "2026-03-28T09:14:23Z"
  }
}

Error (4xx / 5xx)

{
  "error": {
    "code": "not_found",
    "message": "Company not found.",
    "status": 404
  }
}

Rate limit headers

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so you can track your monthly usage.

Tiers

Paid tiers differ on how far back the history goes and how you can get it out. Every paid tier reads every company in the archive.

Tier Price Companies History CSV export Change alerts Raw HTML snapshots API Calls/Month
Free $0 Top 100 Current only No No No 1,000
Starter $99/mo All 12 months back Same 12 months No No 10,000
Pro $299/mo All Full archive, back to January 2021 Full archive Daily email, up to 50 companies No 50,000
Enterprise $799/mo All Full archive, back to January 2021 Full archive Daily email, no company limit Crawled pages only Unlimited

Starter's 12 months is a rolling window counted from today, so it moves forward each day. It applies to /pricing/history and the CSV export alike. January 2021 is where the archive as a whole starts. Individual companies start later and have gaps. Read first_captured and total_snapshots from /v1/companies/:id for a given company's real depth. That endpoint is available on every tier, including free. Change alerts are checked once a day. A day with no change on the companies you follow sends no email. Raw HTML snapshots cover pages the crawler fetched itself, which starts in April 2026. Pricing records recovered from the Internet Archive carry prices and a page hash, but the page itself was never stored, so a company's snapshot list starts when we began crawling it rather than when its pricing history starts.

Endpoints

GET /v1/stats

Returns global statistics about the archive.

Auth: Not required Tier: All

Curl example

curl https://saaspricingarchive.com/v1/stats

Sample response

{
  "data": {
    "total_companies": 500,
    "total_records": 10835,
    "last_crawl": "2026-09-20T02:28:32.325Z",
    "earliest_record": "2021-01-01T00:12:20.000Z"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-04-05T10:00:00Z"
  }
}
GET /v1/companies

Search and list companies in the archive.

Auth: Required Tier: All

Parameters

Name Type Required Description
q string No Search query. Matches company name or domain.
category string No Filter by category slug (e.g., "productivity").
page number No Page number. Default: 1.
per_page number No Results per page. Default: 50. Max: 100.

Curl example

curl "https://saaspricingarchive.com/v1/companies?q=notion&per_page=10" \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": [
    {
      "id": "uuid",
      "name": "Notion",
      "domain": "notion.so",
      "category": "Productivity",
      "pricing_url": "https://notion.so/pricing",
      "is_top_100": true,
      "tier_access_rank": 1
    }
  ],
  "meta": {
    "request_id": "req_abc",
    "timestamp": "..."
  },
  "pagination": {
    "total": 500,
    "page": 1,
    "per_page": 50
  }
}
GET /v1/companies/:id

Get a single company by UUID or domain (e.g., notion.so).

Auth: Required Tier: All

Curl example

curl https://saaspricingarchive.com/v1/companies/notion.so \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"
GET /v1/categories

List all categories with their company counts.

Auth: Required Tier: All

Curl example

curl https://saaspricingarchive.com/v1/categories \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": [
    {
      "name": "Productivity",
      "slug": "productivity",
      "company_count": 47
    }
  ],
  "meta": { ... }
}
GET /v1/categories/:slug/companies

List all companies in a given category.

Auth: Required Tier: All

Parameters

Name Type Required Description
page number No Page number. Default: 1.
per_page number No Results per page. Default: 50. Max: 100.

Curl example

curl "https://saaspricingarchive.com/v1/categories/productivity/companies" \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"
GET /v1/companies/:id/pricing

Latest pricing data for a company. This is the core endpoint. Free keys are limited to the top 100 companies; every paid tier reads every company in the archive.

Auth: Required Tier: Free (top 100), Starter and above (all companies)

Curl example

curl https://saaspricingarchive.com/v1/companies/notion.so/pricing \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": {
    "company": {
      "name": "Notion",
      "domain": "notion.so",
      "category": "Productivity",
      "total_snapshots": 18,
      "pricing_changes_detected": 4,
      "first_captured": "2021-03-01",
      "last_captured": "2026-03-28"
    },
    "captured_at": "2026-03-28T09:14:22Z",
    "source_type": "live_crawl",
    "currency": "USD",
    "free_tier_exists": true,
    "enterprise_plan_exists": true,
    "extraction_confidence": 0.94,
    "plans": [
      {
        "name": "Free",
        "price_monthly": 0,
        "price_annual_per_month": 0,
        "price_unit": null,
        "is_highlighted": false,
        "features": [
          "Unlimited pages & blocks",
          "Share with up to 10 guests",
          "7-day page history"
        ]
      },
      {
        "name": "Plus",
        "price_monthly": 12,
        "price_annual_per_month": 8,
        "price_unit": "user",
        "is_highlighted": true,
        "features": [
          "Unlimited guests",
          "30-day page history",
          "Unlimited file uploads"
        ]
      }
    ]
  },
  "meta": {
    "request_id": "req_7x2k9m",
    "timestamp": "2026-03-28T09:14:23Z"
  }
}
GET /v1/companies/:id/pricing/history

All historical pricing records for a company, ordered newest first. Starter tier is capped to 1 year back. Pro and Enterprise have full history.

Auth: Required Tier: Starter+

Parameters

Name Type Required Description
from string (ISO date) No Start date filter. E.g., 2024-01-01.
to string (ISO date) No End date filter. E.g., 2025-01-01.
cursor string (ISO date) No Pagination cursor. Pass next_cursor from previous response.
limit number No Number of records. Default: 20. Max: 100.

Curl example

curl "https://saaspricingarchive.com/v1/companies/notion.so/pricing/history?limit=5" \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Pagination

Responses include a pagination object with limit, next_cursor, and has_more. Pass next_cursor as the cursor param to fetch the next page.

GET /v1/companies/:id/pricing/changes

Only records where the pricing page changed against the record before it. The comparison runs on the stored page rather than on the extracted prices, so a record can appear here after a page edit that left every price alone. Useful for building change-detection pipelines. Same parameters as /history.

Auth: Required Tier: Starter+

Curl example

curl "https://saaspricingarchive.com/v1/companies/notion.so/pricing/changes" \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"
GET /v1/companies/:id/snapshots

Lists raw HTML snapshot metadata for a company, newest first. Metadata only. Use the id from a row here with the endpoint below to fetch the HTML itself. Only pages the crawler fetched are stored, so this list starts in April 2026 and a company crawled since then has no rows older than that. Records recovered from the Internet Archive have no stored page and never appear here. Each row's source_type says which kind it is, and a company with nothing stored returns an empty list rather than an error.

Auth: Required Tier: Enterprise

Parameters

Name Type Required Description
cursor string No Pagination cursor. Pass next_cursor from the previous response.
limit number No Number of snapshots. Default: 20. Max: 100.

Curl example

curl "https://saaspricingarchive.com/v1/companies/notion.so/snapshots?limit=5" \
          -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
          "data": [
            {
              "id": "8f14e...",
              "captured_at": "2026-03-28T09:14:22Z",
              "source_type": "live_crawl",
              "source_url": "https://notion.so/pricing",
              "byte_length": 618422,
              "html_hash": "b6d767d..."
            }
          ],
          "meta": { ... },
          "pagination": {
            "limit": 20,
            "next_cursor": "MjAyNi0wMy0y...",
            "has_more": true
          }
        }
GET /v1/companies/:id/snapshots/:snapshotId

Returns one snapshot's raw HTML exactly as captured. The snapshot id must belong to the company in the path. An id from a different company returns 404, the same as an id that doesn't exist.

Auth: Required Tier: Enterprise

Curl example

curl https://saaspricingarchive.com/v1/companies/notion.so/snapshots/8f14e... \
          -H "Authorization: Bearer spa_YOUR_API_KEY_HERE" \
          -o snapshot.html

Response

Content-Type: text/html. The body is the stored HTML, unmodified. X-Snapshot-Id and X-Snapshot-Captured-At headers carry the snapshot's id and capture date.

Usage and limits

Each snapshot fetch counts as 10 API calls against your monthly limit, since a single snapshot averages several hundred KB, well above a typical response. Enterprise is unlimited, so this has no practical effect today.

GET /v1/export/pricing.csv

Streams the whole archive (or a filtered slice) as a single CSV file — one row per plan per pricing record — instead of paging through /pricing/history one company at a time. Starter tier is capped to 1 year back, same as /pricing/history.

Auth: Required Tier: Starter+

Parameters

Name Type Required Description
since string (ISO date) No Start date filter. E.g., 2024-01-01.
until string (ISO date) No End date filter. E.g., 2025-01-01.
company string (domain) No Limit to one or more companies. Repeatable, e.g. ?company=notion.so&company=slack.com.
source_type string No Either live_crawl or wayback_bootstrap.

Curl example

curl "https://saaspricingarchive.com/v1/export/pricing.csv?since=2024-01-01" \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE" \
  -o pricing-export.csv

Columns

company_domain, company_name, category, captured_at, source_type, extraction_model, plan_name, price_monthly, price_annual_per_month, currency, pricing_model, unit_price, unit_label, minimum_monthly, is_highlighted, feature_count, record_id — one row per plan per pricing record.

Usage and limits

Each export counts as 25 API calls against your monthly limit, and is capped at 5 exports per day (UTC). A full archive export streams as it's generated rather than loading into memory first, so large exports may take a little while to complete — keep the connection open until it finishes.

GET /v1/account

Returns current account info with usage statistics.

Auth: Required Tier: All

Curl example

curl https://saaspricingarchive.com/v1/account \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": {
    "id": "uuid",
    "email": "[email protected]",
    "tier": "free",
    "api_key_prefix": "spa_abcd1234...",
    "usage": {
      "monthly_calls": 142,
      "monthly_limit": 1000,
      "calls_reset_at": "2026-05-01T00:00:00Z",
      "remaining": 858
    }
  },
  "meta": { ... }
}
POST /v1/account/keys

Rotate your API key. The old key is immediately invalidated. The new key is shown once in the response.

Auth: Required Tier: All

Curl example

curl -X POST https://saaspricingarchive.com/v1/account/keys \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": {
    "api_key": "spa_new_key_here...",
    "prefix": "spa_abcd1234...",
    "message": "New API key generated."
  }
}
POST /v1/upgrade

Upgrade to a paid tier. Returns a Stripe checkout URL. Open it in a browser to complete payment. Your tier updates automatically after payment.

Auth: Required Tier: All

Parameters (JSON body)

Name Type Required Description
tier string Yes Target tier: "starter", "pro", or "enterprise".
success_url string No Redirect URL after successful payment.
cancel_url string No Redirect URL if the user cancels checkout.

Curl example

curl -X POST https://saaspricingarchive.com/v1/upgrade \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"tier": "starter"}'

Sample response

{
  "data": {
    "checkout_url": "https://checkout.stripe.com/c/pay/cs_...",
    "tier": "starter"
  }
}
POST /v1/account/billing-portal

Get a link to the Stripe billing portal. Use it to update your card, cancel, or view invoices. Requires a prior upgrade. Returns 400 if you haven't upgraded yet.

Auth: Required Tier: Starter+

Curl example

curl -X POST https://saaspricingarchive.com/v1/account/billing-portal \
  -H "Authorization: Bearer spa_YOUR_API_KEY_HERE"

Sample response

{
  "data": {
    "portal_url": "https://billing.stripe.com/..."
  }
}

Error codes

All errors return a JSON body with code, message, and status.

Code Status Description
missing_api_key 401 No Authorization header was included in the request.
invalid_api_key 401 Key not found or incorrect.
invalid_api_key_format 401 Key doesn't match the expected spa_ prefix format.
account_inactive 403 Your account has been deactivated.
tier_required 403 This endpoint requires a higher tier. Upgrade at /signup.
rate_limit_exceeded 429 Monthly call limit reached. Resets at the start of your next billing cycle.
export_daily_limit_exceeded 429 You've hit the 5-exports-per-day limit on /export/pricing.csv. Resets at UTC midnight.
validation_error 400 One or more request parameters are invalid. Check the message field for details.
not_found 404 The requested resource was not found.
email_already_registered 409 Signup attempted with an email that already has an account.
invalid_upgrade 400 You are already on this tier or higher.
no_subscription 400 The billing portal requires a prior upgrade.
checkout_error 500 Stripe checkout session creation failed. Try again or contact support.
internal_server_error 500 Unexpected server error. If this persists, contact support.