SmartScopeDocs
Get API key →

User Guide

SmartScope monitors the open-source packages your team depends on and emails you a structured digest every week — new releases, CVEs, and breaking changes, filtered to exactly the packages you care about.

Getting started

After signing up you'll be taken through a short onboarding flow:

  1. Choose a delivery day — pick the weekday you want your digest to arrive (8 am UTC).
  2. Name your first stack — stacks group related packages (e.g. "Frontend", "Backend API").
  3. Add packages — search npm, PyPI, GitHub, or NuGet by name and add them to your stack.

Once onboarding is complete you'll land on your dashboard, where you can manage all your stacks and packages at any time.


Stacks

Stacks let you group packages by context — a frontend app, a backend service, a data pipeline — so your digest is organized around how your stack is actually structured.

Creating a stack

Click + New stack in the top-right of your dashboard. Give the stack a name and, optionally, paste or upload a package.json or requirements.txt to import packages in bulk.

Renaming a stack

Double-click the stack name on the dashboard card. Edit the name inline and press Enter to save, or Escape to cancel.

Deleting a stack

Open the stack card's action menu and choose Delete. You'll be asked to confirm. Deleting a stack removes all of its packages and stops tracking them in future digests.


Adding packages

Packages are added per-stack. Open a stack card and click Add package, or use the bulk import option when creating a new stack.

Supported ecosystems

SourceFormatExample
npmPackage namereact, stripe, @types/node
PyPIPackage namedjango, requests, numpy
GitHubowner/repovercel/next.js, tiangolo/fastapi
NuGetPackage ID (case-insensitive)Newtonsoft.Json, Serilog

SmartScope validates each package against its registry before saving it — you'll see an error immediately if the name isn't found.

Bulk import

When creating a new stack (or via the Import button on an existing stack card) you can paste or drag-and-drop a manifest file. Supported formats:

FileWhat gets imported
package.jsonAll packages in dependencies and devDependencies
requirements.txtAll pinned packages (== specifier only; ranges are skipped)

Packages that already exist in the stack are silently skipped — re-importing is safe.

Removing a package

Click the × next to any package in the stack card. The package is removed immediately and will not appear in future digests.


Weekly digest

Once a week, SmartScope emails you a digest for each stack you've set up. Digests are delivered on the day you chose during onboarding at 8 am UTC.

What's in the digest

SectionDescription
New releasesPackages that published a new version since your last digest
Security advisoriesCVEs affecting a version at or below your last-seen version
Changelog summaryKey bullet points extracted from GitHub release notes (where available)
Up to datePackages with no changes — listed briefly for completeness

CVE severity levels follow the CVSS scale: critical, high, medium, and low. High and critical advisories are highlighted in the email.

Changing your delivery day

Go to Settings and choose a new day under Digest schedule. The change takes effect for the next scheduled run.


Settings

Digest schedule

Choose which day of the week you receive your digest. All digests go out at 8 am UTC regardless of the day selected.

API access

Your API key grants access to the Scan API — a separate REST endpoint for running ad-hoc vulnerability scans from scripts or CI pipelines. Keys are tied to your subscription; generating a new key immediately invalidates the previous one.

The key is shown in full only once at generation time. If you lose it, generate a new one from Settings.


Scan API

The SmartScope Scan API lets you check a manifest against known vulnerabilities and outdated versions from any script or CI/CD pipeline. Send a package.json or requirements.txt, get back a structured report. Gate your deploys on it.


Authentication

All requests to /scan require a Bearer token in the Authorization header. API keys are tied to your account and require an active subscription.

To generate a key: open Settings → API Access and click Generate key. The full key is shown exactly once — copy it into your secret manager before dismissing the dialog.

shell
export SMARTSCOPE_KEY="ss_live_your_key_here"

Store it as an environment secret in your CI provider — never commit it to source control. Keys can be regenerated or revoked at any time from Settings.


The endpoint

http
POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan
Authorization: Bearer <api-key>
Content-Type: application/json

The endpoint always returns HTTP 200. Use the passed field in the response to decide whether to fail your pipeline — see Pipeline control below.


Input formats

The request body is auto-detected. Three formats are supported:

1 — Raw package.json

Post the file directly. Both dependencies and devDependencies are scanned.

shell
curl -s -X POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -H "Content-Type: application/json" \
  -d @package.json

2 — Raw requirements.txt

Only pinned versions (==) are scanned. Range specifiers like >=2.0 are skipped.

shell
curl -s -X POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @requirements.txt

3 — Structured JSON

For multi-ecosystem projects or programmatic use. Supports npm, pypi, and github sources. Maximum 100 packages per request.

json
{
  "packages": [
    { "source": "npm",   "name": "lodash",  "version": "4.14.0" },
    { "source": "pypi",  "name": "django",  "version": "4.1.0"  },
    { "source": "npm",   "name": "express", "version": "4.18.0" }
  ]
}

Response format

json
{
  "summary": {
    "scanned":    3,
    "vulnerable": 1,   // packages with one or more CVEs at your version
    "outdated":   2,   // packages where version !== latestVersion
    "upToDate":   1,
    "critical":   0,
    "high":       1,
    "medium":     0,
    "low":        0
  },
  "packages": [
    {
      "name":          "lodash",
      "source":        "npm",
      "version":       "4.14.0",   // your installed version
      "latestVersion": "4.17.21",  // current registry version
      "upToDate":      false,
      "cves": [
        {
          "id":          "CVE-2021-23337",
          "severity":    "high",
          "summary":     "Command injection via template",
          "fixedIn":     "4.17.21",
          "publishedAt": "2021-02-15T00:00:00Z"
        }
      ]
    }
  ],
  "passed":  false,  // false = at least one CVE at or above failOn threshold
  "failOn":  "critical"
}
FieldTypeDescription
summary.vulnerablenumberPackages with CVEs affecting your specific installed version
summary.outdatednumberPackages where your version differs from the registry latest
packages[].cvesarrayOnly CVEs that affect the version you supplied — not all-time CVEs for the package
passedbooleanfalse when any CVE meets or exceeds the failOn threshold
failOnstringThe threshold used for this scan (echoed from query param)

Pipeline control

Use the ?failOn query parameter to control what severity causes passed: false. Default is critical.

ValueFails on
critical (default)Critical CVEs only
highCritical or high CVEs
mediumCritical, high, or medium CVEs
lowAny CVE
shell
# Fail the pipeline if any high or critical CVE is found
curl -s -X POST "https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan?failOn=high" \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -d @package.json | jq -e '.passed'

jq -e exits with code 1 when the value is false, which fails the pipeline step naturally.


GitHub Actions

The easiest way to get started: generate an API key in Settings, then click Download GitHub workflow. The file includes setup instructions with your key value pre-filled as a comment — add it as a GitHub Secret, drop the file into .github/workflows/, and you're done.

Never commit your API key directly in the workflow file. Store it as a GitHub Secret (repo → Settings → Secrets and variables → Actions) and reference it as ${{ secrets.SMARTSCOPE_API_KEY }}. Committed secrets can be extracted from git history even after deletion.

The downloaded workflow posts a comment on every PR with a scan summary and a table of vulnerable packages. It supports multiple manifest files via the MANIFESTS env var:

yaml
env:
  # Space-separated paths — supports package.json and requirements.txt
  MANIFESTS: "frontend/package.json api/requirements.txt"
  FAIL_ON: "critical"   # critical | high | medium | low

Minimal setup (log-only, no PR comment)

If you already have a workflow and just want to fail the step on CVEs, add this step. Add SMARTSCOPE_API_KEY as a repository secret first.

yaml
- name: SmartScope security scan
  env:
    SMARTSCOPE_API_KEY: ${{ secrets.SMARTSCOPE_API_KEY }}
  run: |
    result=$(curl -sf -X POST \
      "https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan?failOn=high" \
      -H "Authorization: Bearer $SMARTSCOPE_API_KEY" \
      -H "Content-Type: application/json" \
      -d @package.json)

    echo "$result" | jq '.summary'

    if [ "$(echo "$result" | jq -r '.passed')" = "false" ]; then
      echo "::error::SmartScope: vulnerabilities found — see summary above"
      exit 1
    fi

To see per-package details in the Actions log, pipe through jq '.packages[] | select(.cves | length > 0)'.


GitLab CI

Add SMARTSCOPE_KEY as a CI/CD variable under Settings → CI/CD → Variables, masked and protected.

yaml
smartscope-scan:
  stage: test
  image: alpine:latest
  before_script:
    - apk add --no-cache curl jq
  script:
    - |
      result=$(curl -sf -X POST \
        "https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan?failOn=high" \
        -H "Authorization: Bearer $SMARTSCOPE_KEY" \
        -H "Content-Type: application/json" \
        -d @package.json)

      echo "$result" | jq '.summary'

      passed=$(echo "$result" | jq -r '.passed')
      if [ "$passed" = "false" ]; then
        echo "Vulnerabilities found:"
        echo "$result" | jq '.packages[] | select(.cves | length > 0)'
        exit 1
      fi
  only:
    - merge_requests
    - main

Azure DevOps

Add SMARTSCOPE_API_KEY as a secret pipeline variable under Pipelines → Edit → Variables, marked as secret. Save the pipeline below as azure-pipelines.yml at your repo root (or merge the job into an existing pipeline).

Recommended: use a Branch Policy instead of the YAML trigger. Many ADO organizations disable implied YAML PR triggers at the org level, which silently prevents the pr:block from firing. Branch policies are more reliable and block the merge until the scan passes:

  1. Go to Repos → Branches → main → Branch policies
  2. Under Build Validation, click Add
  3. Select your SmartScope pipeline, set trigger to Automatic
  4. Save — the pipeline will now run on every PR targeting main and block merge on failure

The PR comment step uses $(System.AccessToken). For this to work, go to Pipelines → Edit → ⋯ → Triggers → YAML → Get sources and enable Allow scripts to access the OAuth token. Without it the comment post will 401 — the scan itself will still run fine.

yaml
trigger: none  # triggered via Branch Policy, not YAML pr: block

variables:
  MANIFESTS: 'package.json'  # space-separated manifest paths
  FAIL_ON: 'critical'         # critical | high | medium | low

jobs:
  - job: SmartScope
    displayName: SmartScope scan
    pool:
      vmImage: ubuntu-latest

    steps:
      - checkout: self

      - bash: |
          rm -f /tmp/ss-comment.md
          OVERALL_PASSED=true

          for MANIFEST in $(MANIFESTS); do
            if [ ! -f "$MANIFEST" ]; then
              echo "Skipping $MANIFEST — file not found"
              continue
            fi

            RESULT=$(curl -sf \
              -X POST "https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan?failOn=$(FAIL_ON)" \
              -H "Authorization: Bearer $SMARTSCOPE_API_KEY" \
              -H "Content-Type: application/json" \
              --data-binary "@$MANIFEST")

            PASSED=$(echo "$RESULT" | jq -r '.passed')
            SCANNED=$(echo "$RESULT" | jq -r '.summary.scanned')
            VULNERABLE=$(echo "$RESULT" | jq -r '.summary.vulnerable')
            CRITICAL=$(echo "$RESULT" | jq -r '.summary.critical')
            HIGH=$(echo "$RESULT" | jq -r '.summary.high')
            MEDIUM=$(echo "$RESULT" | jq -r '.summary.medium')
            LOW=$(echo "$RESULT" | jq -r '.summary.low')
            OUTDATED=$(echo "$RESULT" | jq -r '.summary.outdated')

            [ "$PASSED" = "false" ] && OVERALL_PASSED=false
            if [ "$PASSED" = "true" ]; then STATUS="Passed"; else STATUS="Failed"; fi

            printf '### %s — %s\n' "$STATUS" "$MANIFEST" >> /tmp/ss-comment.md
            printf '> Scanned **%s** packages · **%s** vulnerable · **%s** outdated  \n' \
              "$SCANNED" "$VULNERABLE" "$OUTDATED" >> /tmp/ss-comment.md
            printf '> Critical: **%s** · High: **%s** · Medium: **%s** · Low: **%s**\n\n' \
              "$CRITICAL" "$HIGH" "$MEDIUM" "$LOW" >> /tmp/ss-comment.md

            VULN_ROWS=$(echo "$RESULT" | jq -r '
              .packages[] | select(.cves | length > 0) |
              "| " + .name + " | " + (.version // "—") + " | " + (.latestVersion // "—") + " | " + (.cves | map(.id + " (" + .severity + ")") | join(", ")) + " |"
            ')

            if [ -n "$VULN_ROWS" ]; then
              printf '| Package | Version | Latest | CVEs |\n|---------|---------|--------|------|\n' >> /tmp/ss-comment.md
              printf '%s\n\n' "$VULN_ROWS" >> /tmp/ss-comment.md
            fi
          done

          printf '%s
' '---' '*[SmartScope](https://mysmartscope.com)*' >> /tmp/ss-comment.md

          if [ -n "$SYSTEM_PULLREQUEST_PULLREQUESTID" ]; then
            PAYLOAD=$(jq -n --rawfile content /tmp/ss-comment.md \
              '{comments:[{parentCommentId:0,content:$content,commentType:1}],status:1}')

            curl -sf -X POST \
              "$SYSTEM_TEAMFOUNDATIONCOLLECTIONURI$SYSTEM_TEAMPROJECT/_apis/git/repositories/$BUILD_REPOSITORY_ID/pullRequests/$SYSTEM_PULLREQUEST_PULLREQUESTID/threads?api-version=7.1" \
              -H "Authorization: Bearer $SYSTEM_ACCESSTOKEN" \
              -H "Content-Type: application/json" \
              -d "$PAYLOAD"
          fi

          [ "$OVERALL_PASSED" = "true" ] || exit 1
        displayName: Scan dependencies and post PR comment
        env:
          SMARTSCOPE_API_KEY: $(SMARTSCOPE_API_KEY)
          SYSTEM_ACCESSTOKEN: $(System.AccessToken)

Shell / curl

Minimal one-liner for local checks or custom scripts:

shell
# Quick scan — prints summary, exits 1 if critical CVEs found
curl -sf -X POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -d @package.json | jq '{summary: .summary, passed: .passed}'

Print only vulnerable packages:

shell
curl -sf -X POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -d @package.json \
  | jq '.packages[] | select(.cves | length > 0) | {name, version, latestVersion, cves}'

Scan a Python project with pinned requirements:

shell
curl -sf -X POST https://rtw7o67sla.execute-api.us-east-1.amazonaws.com/v1/scan \
  -H "Authorization: Bearer $SMARTSCOPE_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @requirements.txt | jq '.summary'

Questions? kaercha.ceo@gmail.com · Get an API key