api

GET /api/audits

List recent audits for your account, deduplicated by URL. Supports limit + offset pagination, ordered by display position then created_at.

What this endpoint does

GET /api/audits returns the most recent audits for the authenticated account, deduplicated by URL. If you’ve audited the same URL ten times, you get one row back: the latest one. The list is ordered by the user’s saved display position (set in the dashboard) and then by created_at descending.

  • Deduplicated by URL: one row per unique URL.
  • Ordered by display_position ASC NULLS LAST, created_at DESC.
  • Returns up to 100 rows by default. No limit or offset parameters in v1; the dashboard fetches the same shape.
  • Cheap and idempotent: no plan cost, no PSI, no crawler call.

Why it matters

This is the endpoint a dashboard, weekly digest, or CI dashboard hits first. It gives every URL the account cares about with its latest score, ready to be linked to GET /api/audits/:id for the full envelope or to POST /api/audits to queue a fresh re-run.

Concrete workflows:

  • A weekly Zapier zap calls GET /api/audits, diffs scores against last week’s snapshot in Airtable, and posts a Slack message for every URL that dropped more than 5 points.
  • An internal CI dashboard polls the endpoint every minute and renders a status grid keyed by display_position so the most important pages show up first.

How to use it

Bearer auth required. No query parameters.

Request

GET /api/audits HTTP/1.1
Host: app.metricspot.com
Authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx

curl

curl https://app.metricspot.com/api/audits \
  -H "authorization: Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Node fetch

const res = await fetch("https://app.metricspot.com/api/audits", {
  headers: { authorization: "Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx" },
});
const { audits } = await res.json();
for (const a of audits) {
  console.log(a.score, a.url);
}

Python httpx

import httpx

r = httpx.get(
    "https://app.metricspot.com/api/audits",
    headers={"authorization": "Bearer ms_live_xxxxxxxxxxxxxxxxxxxxxxxx"},
    timeout=30.0,
)
for a in r.json()["audits"]:
    print(f"{a['score'] or '..'} {a['url']} ({a['status']})")

Response

200 OK:

{
  "audits": [
    {
      "id": 12345,
      "domain": "example.com",
      "url": "https://example.com",
      "status": "completed",
      "score": 78,
      "created_at": "2026-05-14T10:18:04.000Z",
      "completed_at": "2026-05-14T10:18:24.000Z",
      "display_position": 0
    },
    {
      "id": 12321,
      "domain": "example.com",
      "url": "https://example.com/pricing",
      "status": "completed",
      "score": 71,
      "created_at": "2026-05-13T09:02:11.000Z",
      "completed_at": "2026-05-13T09:02:34.000Z",
      "display_position": 1
    }
  ]
}

Fields per row:

  • id: integer audit id, used in follow-up calls.
  • domain: hostname.
  • url: full URL audited.
  • status: one of queued, running, completed, failed.
  • score: integer 0 to 100, or null while queued or running.
  • created_at: ISO 8601 timestamp.
  • completed_at: ISO 8601 timestamp, or null if not yet complete.
  • display_position: integer rank set in the dashboard via drag-and-drop, or null if the user hasn’t reordered. The endpoint orders by this first.

The endpoint always returns {"audits": [...]}. There is no pagination envelope; the cap is 100 rows. Use POST /api/audits followed by GET /api/audits/:id for full per-audit detail.

Error envelope

{ "error": "Unauthorized" }

Common errors

CodeWhenAction
UNAUTHORIZED (401)Missing or invalid Bearer tokenMint a key at app.metricspot.com/settings/api-keys
UPSTREAM_FAILED (5xx)Database hiccupRetry once with backoff

The endpoint never returns 404 or 429: it’s a list of your own resources with no rate limit beyond your plan.

Frequently asked questions

Why is the list deduplicated by URL?

The dashboard shows one card per URL: re-auditing the same URL replaces the previous card’s score. The API mirrors that view exactly so a third-party UI can render the same list without re-implementing the dedupe.

How do I get every audit (including older runs of the same URL)?

Use the per-URL history endpoint exposed in the audit’s detail. The list endpoint is intentionally the “latest per URL” view because that’s what dashboards and digests need. A future revision may expose a flat unpaginated history.

Is display_position editable via the API?

Yes, indirectly: the dashboard’s drag-and-drop maps to a separate reorder endpoint that takes an array of URLs in the new order. The list endpoint reads the saved positions; it doesn’t write them.

Does this count against plan allowance?

No. The list endpoint is unmetered. Only POST /api/audits (and only on success) decrements the monthly counter.

Sources

Last updated 2026-05-14