{
  "openapi": "3.1.1",
  "info": {
    "title": "PageSpeedAudit API",
    "description": "The **PageSpeedAudit API** turns the same expert PageSpeed audit you can buy on the\r\nwebsite into a programmable workflow: hold an audit entitlement, run it against one URL, poll\r\nuntil it finishes, then pull a customer-ready HTML report and a machine-readable findings\r\ndocument (`pagespeed-audit/findings@1`). It's a small, predictable REST API — JSON in, JSON\r\nout, one long-running job type.\r\n\r\nNew here? The [developer portal](https://pagespeedaudit.com/docs) has the five-minute quickstart, the\r\nentitlement lifecycle as a diagram, the findings schema with typed definitions, and the\r\n[error catalog](https://pagespeedaudit.com/docs/errors) every coded error response links to. This page is the\r\ngenerated reference: every operation, every field, and a request console that talks to\r\n**production**.\r\n\r\n## Base URL\r\n\r\n```\r\nhttps://pagespeedaudit.com/api/v1\r\n```\r\n\r\nAll paths below are relative to this base. The API is versioned in the path; breaking changes\r\nship under a new version, never on `v1`. What changed, and when, is on the\r\n[changelog](https://pagespeedaudit.com/docs/changelog).\r\n\r\n## Authentication\r\n\r\nAuthenticate every request with an API key in the **`X-Api-Key`** header:\r\n\r\n```bash\r\ncurl https://pagespeedaudit.com/api/v1/audits \\\r\n  -H \"X-Api-Key: psa_live_your_key_here\"\r\n```\r\n\r\nKeys look like `psa_live_…`, are created and revoked from your dashboard at\r\n`/account/api-keys`, and are shown in full exactly once. Only a SHA-256 hash is stored\r\nserver-side — we cannot recover a lost key, so store it in your secret manager. Treat it like\r\na password: it grants access to your account's audits, and with the `purchase` scope, to\r\nits money.\r\n\r\n> **Server-to-server only.** Never put a `psa_live_…` key in browser JavaScript or a mobile\r\n> app. Call the API from your backend, a serverless function or a trusted automation\r\n> environment. Cross-origin browser access is intentionally not enabled — there is no CORS\r\n> policy — so a page calling the API directly would fail even before it leaked the key.\r\n\r\nKey management itself (`/apikeys`) authenticates with the dashboard session, not a key; an\r\nAPI key that calls it gets `403 dashboard_session_required`.\r\n\r\n## The audit lifecycle\r\n\r\nOne purchase grants one *audit entitlement*: **1 URL, 3 runs (1 + 2 re-runs), valid 30 days\r\nfrom the first run**. Price: $497.\r\n\r\n1. **Hold an entitlement** — buy on the website, send a customer to Checkout\r\n   (`POST /checkout/sessions`), or order on the account (`POST /orders`, `purchase` scope).\r\n2. **Find it** — `GET /audits` lists your entitlements and how many runs remain. An entitlement\r\n   with `url: null` is still unlocked.\r\n3. **Choose the URL** — optional. While the entitlement is unlocked,\r\n   `POST /target-finder/analyses` with `{ \"url\": \"example.com\" }` analyzes the site and\r\n   recommends the page whose audit fixes the most, with alternates; poll\r\n   `GET /target-finder/analyses/{id}`. Once every audit on the account has its URL locked it\r\n   returns `409 url_already_locked`; an account with no active audit gets `403 customers_only`.\r\n4. **Start a run** — `POST /audits/{auditId}/runs` with `{ \"url\": \"https://example.com/\" }`.\r\n   The first run **locks that URL** to the audit and starts the 30-day window; re-runs must\r\n   reuse the same URL. Returns **202 Accepted** with a `runId`.\r\n5. **Poll the run** — `GET /runs/{runId}` until `status` is `Succeeded` (or `Failed`,\r\n   `TimedOut`, `Canceled`). The product's delivery promise is less than 24 hours; poll rather\r\n   than wait on a timer — a few seconds between polls is plenty. `GET /runs/{runId}/events` is a human-readable timeline.\r\n   Or skip polling: add a webhook endpoint (`POST /webhooks`, from a signed-in session) and every\r\n   finished run is POSTed to it as a signed `run.finished` event — see **Webhooks** below.\r\n6. **Fetch the report** — `GET /runs/{runId}/report?format=json` for the findings document, or\r\n   `?format=html` for the rendered, self-contained customer report.\r\n\r\nA failed or timed-out run does **not** consume one of your three runs. The findings document's\r\nschema, a sample assembled from the published worked example, and generated TypeScript, C# and\r\nPython definitions are on the [portal](https://pagespeedaudit.com/docs#reports).\r\n\r\n## Webhooks\r\n\r\nAdd up to 5 `https://` endpoints from **API keys → Webhooks** in the dashboard (or\r\n`POST /webhooks` with a signed-in session; API keys cannot manage webhooks). The response\r\ncarries the endpoint's signing secret **once**. From then on every run on the account that\r\nfinishes — `Succeeded`, `Failed`, `TimedOut` or `Canceled` — is POSTed as JSON:\r\n\r\n```json\r\n{ \"id\": \"<run id>\", \"type\": \"run.finished\", \"createdAt\": \"…\",\r\n  \"data\": { \"runId\": \"…\", \"auditId\": \"…\", \"runNumber\": 2, \"status\": \"Succeeded\",\r\n            \"url\": \"https://example.com/\", \"finishedAt\": \"…\",\r\n            \"runUrl\": \"https://pagespeedaudit.com/api/v1/runs/…\", \"reportUrl\": \"https://pagespeedaudit.com/api/v1/runs/…/report\" } }\r\n```\r\n\r\n`reportUrl` is present only when the run succeeded; fetch it with your API key as usual.\r\nEvery delivery has `PSA-Event-Id`, `PSA-Event-Type` and\r\n`PSA-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" keyed with the secret>`.\r\nRecompute it over the raw body, compare in constant time, and refuse a `t` more than five\r\nminutes old. Answer any 2xx within 10 seconds; anything else (redirects included) is retried\r\nafter 1 and 5 minutes, then 30 minutes, 2, 6, 12 and 24 hours, then given up. The run id is\r\nthe event id, so treat a repeat as already handled. `POST /webhooks/{id}/test` sends a `ping`.\r\n\r\n## Rate limits\r\n\r\nAuthenticated endpoints allow **60 requests per minute per account** (token bucket);\r\n`POST /orders` is limited to **5 requests per minute per account, dry runs included**. Anonymous\r\nendpoints (checkout, newsletter, the referral links) allow **10 requests per minute per IP**.\r\nOver the limit returns **429 Too Many Requests** — back off and retry.\r\n\r\n## Errors\r\n\r\nErrors use [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457) with a stable\r\nmachine-readable `code`, and a `type` that links to that code's entry in the\r\n[error catalog](https://pagespeedaudit.com/docs/errors):\r\n\r\n```json\r\n{\r\n  \"type\": \"https://pagespeedaudit.com/docs/errors#runs_exhausted\",\r\n  \"title\": \"Conflict\",\r\n  \"status\": 409,\r\n  \"detail\": \"All included runs have been used.\",\r\n  \"code\": \"runs_exhausted\"\r\n}\r\n```\r\n\r\nBranch on `code`, never on `detail` — the prose is free to improve. Every refusal the API\r\nmakes on purpose has a code; a `500` is an unhandled failure with no body, and after one on\r\n`POST /orders` you read `GET /orders` before retrying.\r\n\r\n| Status | When |\r\n|---|---|\r\n| `400` | Invalid input — e.g. `url_required`, `invalid_url`, `invalid_format`, `invalid_quantity`, `idempotency_key_required`, `invalid_email` |\r\n| `401` | Missing, malformed or revoked API key (empty body) |\r\n| `402` | A saved card was refused for this attempt — `authentication_required` (the bank wants the cardholder present; the problem carries `orderId` and a `checkoutUrl` to finish in a browser) or `card_declined` (with `orderId`). Nothing was charged, unless `detail` says the charge did not complete |\r\n| `403` | Authenticated but not allowed — `insufficient_scope` names the missing scope; `dashboard_session_required` on key management; `not_an_affiliate`; `customers_only`; `not_agency_owner` when a reseller's team member orders |\r\n| `404` | `not_found`: the resource doesn't exist **or** isn't yours (ownership failures look identical, by design — and a revoked audit's runs answer it too); `report_not_ready` before a run has succeeded; `account_not_found` |\r\n| `409` | State conflict — `url_locked`, `run_in_progress`, `runs_exhausted`, `expired`, `revoked`, `url_already_locked`, `idempotency_key_reused`, `wholesale_unavailable`, `account_email_missing`, `duplicate_key_name`, `key_limit_reached` |\r\n| `429` | Rate limited (empty body), or `daily_limit_reached` / `analysis_limit_reached` on the daily allowances |\r\n| `502` | `checkout_unavailable` — Stripe could not start a Checkout session; nothing was created |\r\n| `503` | `ordering_disabled` / `ordering_paused` / `target_finder_disabled` — temporarily unavailable; nothing was charged |\r\n\r\n## Scopes\r\n\r\nEvery API key carries scopes, chosen when it is created at `/account/api-keys`:\r\n\r\n| Scope | Allows |\r\n|---|---|\r\n| `read` | List audits and runs, read status and timelines, download reports, read past analyses |\r\n| `run` | Start an audit on credit you already hold, its re-runs, and Target Finder analyses |\r\n| `purchase` | Order audit credits — the only scope that can cost money, and never granted implicitly |\r\n\r\nA key created without an explicit list gets `read` and `run`. Calling an operation your key\r\ndoes not carry the scope for returns **403 `insufficient_scope`**, naming the missing scope.\r\n\r\n## Paying for an order\r\n\r\n**Quote first.** `POST /orders` with `{ \"quantity\": 1, \"dryRun\": true }` answers `200` with the\r\neffective unit price (wholesale applied for an approved reseller), the estimated total and the\r\npayment route a real order would take. Nothing is created or charged, and no idempotency key\r\nis needed. It is the request the console below sends by default.\r\n\r\nA real order is paid one of two ways, decided by the account rather than by the request. Save a\r\ncard under **Billing** in the dashboard and consent to off-session charging, and orders are\r\ncharged to it immediately: the response is `202` with `status: paid`, and the credits arrive when\r\nsettlement lands (`status: completed`). With no saved card the response is `201` with a\r\n`checkoutUrl` for someone to pay in a browser. `paymentRoute` on the order says which happened.\r\n\r\n## Idempotency & polling\r\n\r\nOrdering requires an `Idempotency-Key` header: replaying the key returns the original order with\r\n`200` instead of buying again, while reusing it with different parameters returns\r\n`409 idempotency_key_reused`. Starting a run is safe to retry too: a second `POST` while a run is\r\nactive returns `409 run_in_progress` rather than starting a duplicate. Poll `GET /runs/{runId}`\r\n(a few seconds between calls is plenty); there are no webhooks for run completion in `v1`.\r\n\r\n## Support\r\n\r\nQuestions or a higher rate limit? Email the address in the contact block below, or use the\r\n[contact form](https://pagespeedaudit.com/contact).",
    "termsOfService": "https://pagespeedaudit.com/legal/terms",
    "contact": {
      "name": "PageSpeedAudit support",
      "url": "https://pagespeedaudit.com/contact",
      "email": "support@pagespeedaudit.com"
    },
    "license": {
      "name": "Proprietary — © 2026 PageSpeedAudit"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://pagespeedaudit.com",
      "description": "Production — the only environment; requests here are real"
    }
  ],
  "paths": {
    "/api/v1/checkout/sessions": {
      "post": {
        "tags": [
          "Checkout"
        ],
        "summary": "Start a checkout",
        "description": "Creates a hosted Stripe Checkout session and returns its URL. Redirect the buyer there; on payment, an audit entitlement is created for their email. Pass `email` to prefill the buyer's address. This is the anonymous purchase route — for an authenticated account, `POST /orders` places the order on the account instead. An address that cannot receive the audit is `400 unusable_email`; a Stripe outage is `502 checkout_unavailable` (nothing was created).",
        "operationId": "createCheckoutSession",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/CreateCheckoutRequest"
                  }
                ]
              },
              "example": {
                "email": "buyer@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateCheckoutResponse"
                },
                "example": {
                  "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_…"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contact": {
      "post": {
        "tags": [
          "Contact"
        ],
        "summary": "Send a contact message",
        "description": "Acknowledges the sender by email; genuine (non-spam) messages are forwarded internally after an automated classification. Authenticated — an API key or the dashboard session — because each message is classified; the website's own form uses a separate, spam-challenged route. The message is filed under the authenticated account's address: `email` may be omitted, and a different address is `400 email_mismatch`. An empty or over-long message is `400 invalid_message`. An API key needs the `read` scope (`403 insufficient_scope` otherwise); a key without `run` files the message as an unverified ticket, so support will ask for confirmation before acting on the account.",
        "operationId": "submitContact",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/r/{code}": {
      "get": {
        "tags": [
          "Referral links"
        ],
        "summary": "Referral link",
        "description": "The affiliate referral link. Sets the signed 30-day last-click attribution cookie and redirects. Optional query parameters: `to` (internal path to land on, e.g. `/pricing` — external URLs fall back to `/`), `subid` (also `clickid`/`s1`; your own click id, echoed in reporting and postbacks), `s2`-`s5` (four more slots for the levels you bid at — keyword, ad group, creative, placement — stored on the click and echoed back on the postback), `campaign` (a broader reporting bucket) and `coupon` (one of your own coupon codes — pre-applied at checkout so the buyer sees the discount without typing it). Unknown or suspended codes redirect without setting anything.",
        "operationId": "referralRedirect",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Found"
          }
        }
      }
    },
    "/r/{code}/buy": {
      "get": {
        "tags": [
          "Referral links"
        ],
        "summary": "Direct checkout link",
        "description": "Sends the visitor straight to Stripe Checkout with your commission attribution attached to the session itself — nothing is stored on their device, so EU visitors see no consent step. Credit applies to purchases completed from this click (no attribution window). Optional query parameters: `coupon` (one of your own coupon codes, pre-applied so the buyer sees the discount without typing), `subid` (also `clickid`/`s1`) and `campaign`. Unknown or suspended codes redirect to /pricing without attribution.",
        "operationId": "directCheckout",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Found"
          }
        }
      }
    },
    "/r/{code}/lead": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Open the storage-free audit-opportunity flow",
        "description": "Carries affiliate attribution in a short-lived signed form token without creating a 30-day browser cookie.",
        "operationId": "affiliateLeadEntry",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/me": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "Who am I",
        "description": "Returns the authenticated account and the list of audit entitlements it owns.",
        "operationId": "getMe",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeDto"
                },
                "example": {
                  "userId": "0199b4b0-2c7d-7f4a-9e1b-5a3c8d2e6f01",
                  "email": "integrations@example.com",
                  "audits": [
                    {
                      "id": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e43",
                      "url": null,
                      "status": "Active",
                      "runsAllowed": 3,
                      "runsUsed": 0,
                      "runsRemaining": 3,
                      "hasActiveRun": false,
                      "urlLockedAtUtc": null,
                      "expiresAtUtc": null,
                      "createdAtUtc": "2026-09-01T16:02:41Z"
                    }
                  ]
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/audits": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "List audits",
        "description": "Lists every audit entitlement on the account, with runs used/remaining and expiry.",
        "operationId": "listAudits",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditDto"
                  }
                },
                "example": [
                  {
                    "id": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e43",
                    "url": null,
                    "status": "Active",
                    "runsAllowed": 3,
                    "runsUsed": 0,
                    "runsRemaining": 3,
                    "hasActiveRun": false,
                    "urlLockedAtUtc": null,
                    "expiresAtUtc": null,
                    "createdAtUtc": "2026-09-01T16:02:41Z"
                  },
                  {
                    "id": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e42",
                    "url": "https://example.com/",
                    "status": "Active",
                    "runsAllowed": 3,
                    "runsUsed": 1,
                    "runsRemaining": 2,
                    "hasActiveRun": false,
                    "urlLockedAtUtc": "2026-09-02T09:14:07Z",
                    "expiresAtUtc": "2026-10-02T09:14:07Z",
                    "createdAtUtc": "2026-09-01T16:02:41Z"
                  }
                ]
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/audits/{auditId}": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "Get an audit",
        "description": "Fetches one audit by id. Returns `404 not_found` if it does not exist or belongs to another account — the two cases are deliberately indistinguishable.",
        "operationId": "getAudit",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditDto"
                },
                "example": {
                  "id": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e42",
                  "url": "https://example.com/",
                  "status": "Active",
                  "runsAllowed": 3,
                  "runsUsed": 1,
                  "runsRemaining": 2,
                  "hasActiveRun": false,
                  "urlLockedAtUtc": "2026-09-02T09:14:07Z",
                  "expiresAtUtc": "2026-10-02T09:14:07Z",
                  "createdAtUtc": "2026-09-01T16:02:41Z"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/audits/{auditId}/runs": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "List runs of an audit",
        "description": "Lists every run of one audit, newest first, with the report formats available for each.",
        "operationId": "listRuns",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RunDto"
                  }
                },
                "example": [
                  {
                    "id": "0199b4c9-1a5f-7c02-8b4d-6e7f2a9c0d13",
                    "auditId": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e42",
                    "runNumber": 1,
                    "status": "Succeeded",
                    "queuedAtUtc": "2026-09-02T09:14:07Z",
                    "startedAtUtc": "2026-09-02T09:14:20Z",
                    "finishedAtUtc": "2026-09-02T09:31:52Z",
                    "errorCode": null,
                    "availableReportFormats": [
                      "json",
                      "html"
                    ]
                  }
                ]
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Audits"
        ],
        "summary": "Start an audit run",
        "description": "Queues a run. On the **first** run, pass `url` — it gets locked to this audit and starts the\r\n30-day window; re-runs must reuse the same URL. Up to 3 runs total (1 + 2 re-runs). Returns\r\n**202 Accepted** with the `runId`; poll `GET /runs/{runId}` for completion. Conflicts\r\n(`url_locked`, `run_in_progress`, `runs_exhausted`, `expired`, `revoked`) return 409.\r\nA failed or timed-out run does not consume one of the included runs. Requires the `run` scope.",
        "operationId": "createRun",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/CreateRunRequest"
                  }
                ]
              },
              "example": {
                "url": "https://example.com/"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateRunResponse"
                },
                "example": {
                  "runId": "0199b4c9-1a5f-7c02-8b4d-6e7f2a9c0d13",
                  "auditId": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e42",
                  "runNumber": 1,
                  "status": "Queued"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#url_locked",
                  "title": "Conflict",
                  "status": 409,
                  "detail": "This audit is locked to its first-run URL; re-runs must use the same URL.",
                  "code": "url_locked"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/runs/{runId}": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "Get run status",
        "description": "Returns the run's status and timestamps. `status` moves `Queued` → `Starting` → `Running` and ends in `Succeeded`, `Failed`, `TimedOut` or `Canceled`; poll every few seconds until it is terminal, then fetch the report when it is `Succeeded`. No token or cost data is ever included.",
        "operationId": "getRun",
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunDto"
                },
                "example": {
                  "id": "0199b4c9-1a5f-7c02-8b4d-6e7f2a9c0d13",
                  "auditId": "0199b4c2-6e2a-7d31-9f0e-3b8a5c1d7e42",
                  "runNumber": 1,
                  "status": "Succeeded",
                  "queuedAtUtc": "2026-09-02T09:14:07Z",
                  "startedAtUtc": "2026-09-02T09:14:20Z",
                  "finishedAtUtc": "2026-09-02T09:31:52Z",
                  "errorCode": null,
                  "availableReportFormats": [
                    "json",
                    "html"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/runs/{runId}/events": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "Get run timeline",
        "description": "Returns the human-readable progress timeline of a run (summaries only).",
        "operationId": "getRunEvents",
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RunEventDto"
                  }
                },
                "example": [
                  {
                    "type": "StatusRunning",
                    "summary": "Session started",
                    "createdAtUtc": "2026-09-02T09:14:07Z"
                  },
                  {
                    "type": "ToolUse",
                    "summary": "Fetching PageSpeed Insights and CrUX field data",
                    "createdAtUtc": "2026-09-02T09:14:20Z"
                  },
                  {
                    "type": "AgentMessage",
                    "summary": "Adjudicating 21 flags against the field data",
                    "createdAtUtc": "2026-09-02T09:22:05Z"
                  },
                  {
                    "type": "StatusIdle",
                    "summary": "Report rendered: findings.json + report.html",
                    "createdAtUtc": "2026-09-02T09:31:52Z"
                  }
                ]
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/runs/{runId}/report": {
      "get": {
        "tags": [
          "Audits"
        ],
        "summary": "Download the report",
        "description": "Streams a deliverable for a succeeded run. `format=json` returns the machine-readable findings\r\ndocument (schema `pagespeed-audit/findings@1`); `format=html` returns the rendered, self-contained\r\ncustomer report. `inline=true` streams without an attachment disposition (for embedding).\r\nBefore the run has succeeded there is nothing to stream: `404 report_not_ready`.",
        "operationId": "getRunReport",
        "parameters": [
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "inline",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#report_not_ready",
                  "title": "Not Found",
                  "status": 404,
                  "detail": "The report is not available for this run.",
                  "code": "report_not_ready"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/login-wall": {
      "post": {
        "tags": [
          "Signed-in audits"
        ],
        "summary": "Does this page need a login?",
        "description": "Checks whether a page sits behind a login, the same check the dashboard runs when a URL is\r\nentered. `verdict` is `public`, `login_required`, `http_authentication` (the browser's own\r\npassword prompt, which signed-in audits cannot pass) or `unknown`. `loginUrl` is the login\r\npage visitors were sent to, when one was seen.",
        "operationId": "detectLoginWall",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginWallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginWallDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/audits/{auditId}/access": {
      "get": {
        "tags": [
          "Signed-in audits"
        ],
        "summary": "Get signed-in access",
        "description": "Returns how this audit signs in to a page behind a login. The password and cookie are never returned.",
        "operationId": "getAuditAccess",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Signed-in audits"
        ],
        "summary": "Give access to a page behind a login",
        "description": "Stores how the audit signs in — a test account (`method: \"form\"`, with `loginUrl`, `username`,\r\n`password`) or a session cookie (`method: \"cookie\"`, with `cookie` as copied from the browser) —\r\nthen signs in once to check it. The response carries the check's `outcome` (`ok`, or the reason\r\nit failed, with a fix). Access is stored encrypted, never returned, and deleted when the audit's\r\nwindow ends. For an audit without a locked URL yet, pass the page as `url`. Requires the `run` scope.",
        "operationId": "saveAuditAccess",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveAccessRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaveAccessResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Signed-in audits"
        ],
        "summary": "Remove signed-in access",
        "description": "Deletes the stored access at once. Later runs audit the page signed out. Requires the `run` scope.",
        "operationId": "deleteAuditAccess",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/audits/{auditId}/access/check": {
      "post": {
        "tags": [
          "Signed-in audits"
        ],
        "summary": "Check signed-in access again",
        "description": "Signs in once more with the stored access and reports the `outcome` — for example before a re-run, or after a run reported that it could not sign in (`checkedByRun` on the access). Requires the `run` scope.",
        "operationId": "checkAuditAccess",
        "parameters": [
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessCheckDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/target-finder/analyses": {
      "post": {
        "tags": [
          "Target Finder"
        ],
        "summary": "Analyze your site to find the page to audit",
        "description": "Queues an analysis of your site: robots → sitemap → homepage, URL templates, candidate\r\nprobes (including whether Google CrUX holds field data for each page), and one\r\nrecommendation with alternates. Available while an audit on the account still has an\r\n**unlocked** URL — after the first run locks it, creation returns `409 url_already_locked`.\r\nReturns **202 Accepted** with the analysis (an instantly-served cached result may already be\r\n`Succeeded`); poll `GET /target-finder/analyses/{id}` until `status` is `Succeeded` or\r\n`Failed`. Typical duration: under a minute.",
        "operationId": "createTargetAnalysis",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/CreateTargetAnalysisRequest"
                  }
                ]
              },
              "example": {
                "url": "example.com"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TargetAnalysisDto"
                },
                "example": {
                  "id": "0199b4d4-9c3b-7e58-a1f4-7b2c8d0e5f91",
                  "origin": "https://example.com",
                  "status": "Queued",
                  "stage": "Queued",
                  "urlsSeen": 0,
                  "templatesFound": 0,
                  "candidatesProbed": 0,
                  "sitemapUsed": false,
                  "advisor": "none",
                  "failureCode": null,
                  "requestedAtUtc": "2026-09-02T09:14:07Z",
                  "completedAtUtc": null,
                  "recommendation": null
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#url_already_locked",
                  "title": "Conflict",
                  "status": 409,
                  "detail": "Every audit on this account already has its URL locked — the Target Finder's moment is before the first run.",
                  "code": "url_already_locked"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Target Finder"
        ],
        "summary": "List analyses",
        "description": "Lists the account's analyses, newest first (up to 20).",
        "operationId": "listTargetAnalyses",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TargetAnalysisDto"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/target-finder/analyses/{analysisId}": {
      "get": {
        "tags": [
          "Target Finder"
        ],
        "summary": "Get an analysis",
        "description": "Returns the analysis' live `stage` (Queued → Discovering → Clustering → Probing → Adjudicating → Done) and, once `status` is `Succeeded`, the recommendation. `404 not_found` if it does not exist or belongs to another account. Past analyses stay readable after your audit URL locks.",
        "operationId": "getTargetAnalysis",
        "parameters": [
          {
            "name": "analysisId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TargetAnalysisDto"
                },
                "example": {
                  "id": "0199b4d4-9c3b-7e58-a1f4-7b2c8d0e5f91",
                  "origin": "https://example.com",
                  "status": "Succeeded",
                  "stage": "Done",
                  "urlsSeen": 412,
                  "templatesFound": 7,
                  "candidatesProbed": 9,
                  "sitemapUsed": true,
                  "advisor": "llm",
                  "failureCode": null,
                  "requestedAtUtc": "2026-09-02T09:14:07Z",
                  "completedAtUtc": "2026-09-02T09:14:58Z",
                  "recommendation": {
                    "siteKind": "shop",
                    "primary": {
                      "url": "https://example.com/products/example-product",
                      "templateLabel": "Product page",
                      "templateSharePercent": 61.4,
                      "reason": "The template most of the site's URLs share, with page-level CrUX field data.",
                      "fieldData": "page",
                      "httpStatus": 200,
                      "navLinked": true,
                      "whenToPrefer": null
                    },
                    "alternates": [
                      {
                        "url": "https://example.com/",
                        "templateLabel": "Homepage",
                        "templateSharePercent": 0.2,
                        "reason": "Field data at page level; a fix here reaches every visitor who lands on it.",
                        "fieldData": "page",
                        "httpStatus": 200,
                        "navLinked": true,
                        "whenToPrefer": "When the homepage is the main paid-traffic landing page."
                      }
                    ],
                    "homepageNote": "The homepage is one template among several; the product template carries most of the traffic."
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/apikeys": {
      "get": {
        "tags": [
          "API keys"
        ],
        "summary": "List API keys",
        "description": "Lists the account's API keys — prefixes, scopes and metadata only; the secret is never retrievable. Dashboard session required: an API key gets `403 dashboard_session_required`.",
        "operationId": "listApiKeys",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiKeyDto"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "DashboardSession": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "API keys"
        ],
        "summary": "Create an API key",
        "description": "Creates a key and returns the plaintext secret **exactly once** — store it immediately.\r\nDashboard session required (API keys cannot create keys). `scopes` chooses the key's\r\nauthority: `read` (list audits, runs and reports), `run` (start audits and re-runs) and\r\n`purchase` (order audits). Omitting it grants `read` and `run` — `purchase` is never\r\nimplicit, because it is the only scope that can cost money. Returns `409 duplicate_key_name`\r\nif an active key already uses the name, `409 key_limit_reached` at the account's key limit,\r\nand `400 unknown_scope` for a scope that does not exist.",
        "operationId": "createApiKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              },
              "example": {
                "name": "ci-pipeline",
                "scopes": [
                  "read",
                  "run"
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateApiKeyResponse"
                },
                "example": {
                  "id": "0199b4e0-7d2a-7b93-8c1f-4e6a2b5d9c37",
                  "name": "ci-pipeline",
                  "keyPrefix": "psa_live_3fQ",
                  "key": "psa_live_3fQ…",
                  "scopes": [
                    "read",
                    "run"
                  ],
                  "notice": "Store this key now — it cannot be shown again."
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#dashboard_session_required",
                  "title": "Forbidden",
                  "status": 403,
                  "detail": "API keys are managed from a signed-in dashboard session, never by an API key. Open /account/api-keys.",
                  "code": "dashboard_session_required"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "DashboardSession": [ ]
          }
        ]
      }
    },
    "/api/v1/apikeys/{keyId}": {
      "delete": {
        "tags": [
          "API keys"
        ],
        "summary": "Revoke an API key",
        "description": "Immediately revokes a key by id. Returns 204 on success, `404 not_found` if the key isn't on this account. Dashboard session required.",
        "operationId": "revokeApiKey",
        "parameters": [
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "DashboardSession": [ ]
          }
        ]
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook endpoints",
        "description": "The account's webhook endpoints. The signing secret is never returned again after creation, only its first characters. Dashboard session required.",
        "operationId": "listWebhooks",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointDto"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Add a webhook endpoint",
        "description": "Registers an `https://` URL on a public address. Every run on the account that finishes\r\nafterwards (`Succeeded`, `Failed`, `TimedOut` or `Canceled`) is POSTed to it as a\r\n`run.finished` event, signed with the secret returned here **exactly once**. Up to 5\r\nendpoints per account. `400 invalid_webhook_url` for a URL that is not https or not\r\npublic, `409 webhook_limit_reached` at the limit. Dashboard session required.",
        "operationId": "createWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateWebhookResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{webhookId}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook endpoint",
        "description": "Stops all delivery to it at once, including retries still waiting. 204 on success, `404 not_found` if it is not on this account. Dashboard session required.",
        "operationId": "deleteWebhook",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{webhookId}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test event",
        "description": "Queues a signed `ping` event to the endpoint, delivered within seconds, so the receiver and its signature check can be tried without waiting for a run. 202 when queued. Dashboard session required.",
        "operationId": "testWebhook",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted"
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/orders": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Order audits (production — may charge a saved card)",
        "description": "> **Production operation.** Without `dryRun`, this places a real order on the account.\r\n> If the account has a saved card with an off-session mandate, **the card is charged\r\n> immediately**. The example request below is a dry run; remove `\"dryRun\": true` only when\r\n> you mean to order.\r\n\r\n**Quote first.** Send `{ \"quantity\": 1, \"dryRun\": true }` and the response is a `200` quote:\r\nthe effective unit price (wholesale applied if the account is an approved reseller), the\r\nestimated total, and the payment route a real order would take — `charge` (saved card,\r\nimmediate) or `link` (Checkout URL). Nothing is created, Stripe is not called, and no\r\n`Idempotency-Key` is needed.\r\n\r\n**Then order.** Creates an order for `quantity` audits and returns a Stripe Checkout URL to pay it.\r\nPayment is a browser step: send the buyer to `checkoutUrl`. Once it is paid, the order's\r\naudits appear on `GET /audits` as unspent credit — each one becomes a running audit when\r\nyou `POST /audits/{id}/runs` with a URL.\r\n\r\nIf the account is an **approved reseller**, the wholesale price is applied automatically\r\nand server-side; there is no code to type and none can be supplied by the caller. If the\r\nwholesale code cannot be applied the order **fails** rather than quietly billing at list\r\nprice.\r\n\r\n**If the account has saved a card** at `/account/billing` and consented to off-session\r\ncharging, the order is charged immediately instead: the response is `202` with\r\n`status: paid` and no `checkoutUrl`, and the credits appear once settlement lands\r\n(normally seconds — poll `GET /orders/{orderId}` until `status` is `completed`). A card\r\nthe bank will only take with the cardholder present returns `402 authentication_required`\r\nwith the recorded order's `orderId` and a `checkoutUrl` to finish it in a browser; nothing\r\nwas charged. A declined card returns `402 card_declined` with the `orderId`: nothing was\r\ncharged — unless `detail` says the charge did not complete, in which case the outcome is\r\nunknown and you read `GET /orders/{orderId}` before retrying.\r\n\r\nRequires an API key with the `purchase` scope — a signed-in dashboard session is refused\r\nwith `403 api_key_required`, so the request console on this page cannot order while you\r\nare merely signed in. An **`Idempotency-Key` header is required** for a real order: replaying it returns the original order (`200`) instead of\r\ncreating a second one, while reusing it with different parameters is a `409`. Bursts are\r\nlimited to 5 requests per minute to this operation per account, dry runs included; the\r\naccount's daily ceilings answer `429 daily_limit_reached`.\r\n\r\nOrder `status`: `created` (payable, nothing charged) → `paid` (charge route: the card was\r\ncharged, settlement pending) → `completed` (the credits are on the account); a refused\r\ncharge is `failed` with `failureCode`.\r\n\r\nThe `200` response is therefore one of two shapes: the quote (`dryRun`) or the replayed\r\noriginal order (idempotent retry).",
        "operationId": "createOrder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/CreateOrderRequest"
                  }
                ]
              },
              "example": {
                "quantity": 1,
                "dryRun": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderDto"
                },
                "example": {
                  "id": "0199b4d0-4f8e-7a16-b3c2-1d5e9f6a8b70",
                  "quantity": 1,
                  "unitAmountCents": 49700,
                  "estimatedTotalCents": 49700,
                  "currency": "usd",
                  "wholesale": false,
                  "discountPercent": null,
                  "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_…",
                  "status": "created",
                  "paymentRoute": "link",
                  "failureCode": null,
                  "failureMessage": null,
                  "createdAtUtc": "2026-09-02T09:14:07Z",
                  "completedAtUtc": null
                }
              }
            }
          },
          "200": {
            "description": "Dry run: the quote (nothing created). Idempotent replay: the original order.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OrderQuoteDto"
                    },
                    {
                      "$ref": "#/components/schemas/OrderDto"
                    }
                  ],
                  "description": "For `dryRun: true`, the quote. For a replayed Idempotency-Key, the original order."
                },
                "example": {
                  "dryRun": true,
                  "quantity": 1,
                  "unitAmountCents": 49700,
                  "estimatedTotalCents": 49700,
                  "currency": "usd",
                  "wholesale": false,
                  "discountPercent": null,
                  "paymentRoute": "link",
                  "cardBrand": null,
                  "cardLast4": null,
                  "notice": "Dry run — nothing was created or charged. A real order with these parameters would answer 201 with a Checkout URL to pay in a browser."
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderDto"
                },
                "example": {
                  "id": "0199b4d0-4f8e-7a16-b3c2-1d5e9f6a8b70",
                  "quantity": 1,
                  "unitAmountCents": 29820,
                  "estimatedTotalCents": 29820,
                  "currency": "usd",
                  "wholesale": true,
                  "discountPercent": 40,
                  "checkoutUrl": null,
                  "status": "paid",
                  "paymentRoute": "charge",
                  "failureCode": null,
                  "failureMessage": null,
                  "createdAtUtc": "2026-09-02T09:14:07Z",
                  "completedAtUtc": null
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#authentication_required",
                  "title": "Payment Required",
                  "status": 402,
                  "detail": "This card needs the cardholder to authenticate. Nothing was charged — open checkoutUrl to finish the order in a browser.",
                  "code": "authentication_required",
                  "orderId": "0199b4d0-4f8e-7a16-b3c2-1d5e9f6a8b70",
                  "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_…"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#idempotency_key_reused",
                  "title": "Conflict",
                  "status": 409,
                  "detail": "This Idempotency-Key was already used for an order with different parameters.",
                  "code": "idempotency_key_reused"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "List recent orders",
        "description": "The 50 most recent orders on this account, newest first.",
        "operationId": "listOrders",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OrderDto"
                  }
                },
                "example": [
                  {
                    "id": "0199b4d0-4f8e-7a16-b3c2-1d5e9f6a8b70",
                    "quantity": 1,
                    "unitAmountCents": 49700,
                    "estimatedTotalCents": 49700,
                    "currency": "usd",
                    "wholesale": false,
                    "discountPercent": null,
                    "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_…",
                    "status": "completed",
                    "paymentRoute": "link",
                    "failureCode": null,
                    "failureMessage": null,
                    "createdAtUtc": "2026-09-02T09:14:07Z",
                    "completedAtUtc": "2026-09-02T09:31:52Z"
                  }
                ]
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/orders/{orderId}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "summary": "Get an order",
        "description": "Fetches one order. `status` is `created` while it is payable (nothing charged yet); the charge route moves it to `paid` the moment the card is charged; settlement moves either route to `completed`, when the credits are on the account. A refused charge is `failed` with `failureCode`. `404 not_found` if the order is not on this account.",
        "operationId": "getOrder",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderDto"
                },
                "example": {
                  "id": "0199b4d0-4f8e-7a16-b3c2-1d5e9f6a8b70",
                  "quantity": 1,
                  "unitAmountCents": 49700,
                  "estimatedTotalCents": 49700,
                  "currency": "usd",
                  "wholesale": false,
                  "discountPercent": null,
                  "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_…",
                  "status": "completed",
                  "paymentRoute": "link",
                  "failureCode": null,
                  "failureMessage": null,
                  "createdAtUtc": "2026-09-02T09:14:07Z",
                  "completedAtUtc": "2026-09-02T09:31:52Z"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/newsletter/subscribe": {
      "post": {
        "tags": [
          "Newsletter"
        ],
        "summary": "Subscribe to the newsletter",
        "description": "Double opt-in: a confirmation email is sent. The response is identical whether or not the address was already subscribed (no subscriber enumeration). A malformed address is `400 invalid_email`; a temporary inbox is `400 disposable_email`.",
        "operationId": "subscribeNewsletter",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscribeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/affiliate/me": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Your affiliate profile",
        "description": "Referral code + link, effective commission rate, attribution window, discount coupons, payout-onboarding state, and the current postback configuration. Every affiliate operation answers `403 not_an_affiliate` for an account without an active affiliate profile.",
        "operationId": "affiliateMe",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateMeResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/affiliate/stats": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Your traffic & earnings stats",
        "description": "Clicks (bots excluded), unique visitors, conversions, conversion rate, EPC, and lifetime earnings by status. `from`/`to` bound the period ([inclusive, exclusive); default all time). Pass `groupBy=subid` or `groupBy=campaign` for the per-placement breakdown — which content converts. `leads` carries lead attribution — unconfirmed, confirmed, and how many confirmed leads have since bought, split by source; these are lifetime figures and ignore `from`/`to`, because a lead does not expire. Invalid input is `400` with code `invalid_date` or `invalid_group_by`.",
        "operationId": "affiliateStats",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateStatsResponse"
                },
                "example": {
                  "fromUtc": null,
                  "toUtc": null,
                  "clicks": 0,
                  "uniqueVisitors": 0,
                  "conversions": 0,
                  "reversed": 0,
                  "conversionRatePercent": 0,
                  "epcCents": 0,
                  "earnings": {
                    "pendingCents": 0,
                    "approvedCents": 0,
                    "paidCents": 0,
                    "reversedCents": 0
                  },
                  "groupBy": null,
                  "groups": null,
                  "leads": {
                    "unconfirmed": 0,
                    "confirmed": 0,
                    "converted": 0,
                    "bySource": [ ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "example": {
                  "type": "https://pagespeedaudit.com/docs/errors#not_an_affiliate",
                  "title": "Forbidden",
                  "status": 403,
                  "detail": "This account has no active affiliate profile. Join at /affiliates.",
                  "code": "not_an_affiliate"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/affiliate/recruiting": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Your recruit-an-affiliate program",
        "description": "Recruit affiliates with your recruit link and receive a first-level override commission — a percent of the net audit revenue each recruit's referred sales generate, for the life of their program. Overrides mature, reverse on refunds and pay out exactly like sale commissions. Recruits are listed without identity: join date, status and the override their sales produced.",
        "operationId": "affiliateRecruiting",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateRecruitingResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/affiliate/referrals": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Your conversions",
        "description": "Your referred sales and their commissions, newest first, 50 per page. Filter with `status=` (pending | approved | reversed | paid). No buyer data is exposed — only amounts, dates, and your own subid/campaign tags. An unknown `status` is `400 invalid_status`.",
        "operationId": "affiliateReferrals",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateReferralsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/affiliate/payouts": {
      "get": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Your payout history",
        "description": "Every payout made to this affiliate, newest first: amount, the number of referrals it settled, and its status.",
        "operationId": "affiliatePayouts",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AffiliatePayoutDto"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    },
    "/api/v1/affiliate/postback": {
      "put": {
        "tags": [
          "Affiliate"
        ],
        "summary": "Configure your S2S postback",
        "description": "Set the server-to-server conversion callback: an https URL on a public host (validated), plus which events fire it (sale, approved, reversed; default sale). Macros like {click_id}, {transaction_id}, {sale_amount}, {commission}, {status} are substituted at delivery. Send an empty url to clear the configuration. A private, non-https or otherwise unusable URL is `400 invalid_postback_url`; an unknown event name is `400 invalid_postback_events`.",
        "operationId": "affiliateSetPostback",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AffiliatePostbackUpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliatePostbackDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AccessCheckDto": {
        "required": [
          "outcome",
          "ok",
          "message",
          "fix",
          "finalUrl"
        ],
        "type": "object",
        "properties": {
          "outcome": {
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          },
          "fix": {
            "type": "string"
          },
          "finalUrl": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "AccessDto": {
        "required": [
          "method",
          "targetUrl",
          "loginUrl",
          "usernameHint",
          "signedInCheck",
          "extraHosts",
          "blurScreenshots",
          "checkOutcome",
          "checkedAtUtc",
          "checkedByRun",
          "checkMessage",
          "checkFix"
        ],
        "type": "object",
        "properties": {
          "method": {
            "type": "string"
          },
          "targetUrl": {
            "type": "string"
          },
          "loginUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "usernameHint": {
            "type": [
              "null",
              "string"
            ]
          },
          "signedInCheck": {
            "type": [
              "null",
              "string"
            ]
          },
          "extraHosts": {
            "type": [
              "null",
              "string"
            ]
          },
          "blurScreenshots": {
            "type": "boolean"
          },
          "checkOutcome": {
            "type": [
              "null",
              "string"
            ]
          },
          "checkedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "checkedByRun": {
            "type": "boolean"
          },
          "checkMessage": {
            "type": [
              "null",
              "string"
            ]
          },
          "checkFix": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "AffiliateCouponDto": {
        "required": [
          "percent",
          "code"
        ],
        "type": "object",
        "properties": {
          "percent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "code": {
            "type": "string"
          }
        }
      },
      "AffiliateEarningsDto": {
        "required": [
          "pendingCents",
          "approvedCents",
          "paidCents",
          "reversedCents"
        ],
        "type": "object",
        "properties": {
          "pendingCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "approvedCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "paidCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "reversedCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "inTransitCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64",
            "default": 0
          }
        }
      },
      "AffiliateGroupDto": {
        "required": [
          "key",
          "clicks",
          "uniqueVisitors",
          "conversions",
          "conversionRatePercent",
          "earnedCents",
          "epcCents"
        ],
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "clicks": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "uniqueVisitors": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "conversions": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "conversionRatePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "earnedCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "epcCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "AffiliateLeadsDto": {
        "required": [
          "unconfirmed",
          "confirmed",
          "converted",
          "bySource"
        ],
        "type": "object",
        "properties": {
          "unconfirmed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "confirmed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "converted": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "bySource": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateLeadSourceDto"
            }
          }
        }
      },
      "AffiliateLeadSourceDto": {
        "required": [
          "source",
          "unconfirmed",
          "confirmed",
          "converted",
          "confirmRatePercent",
          "buyRatePercent"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "unconfirmed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "confirmed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "converted": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "confirmRatePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "buyRatePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "AffiliateMeResponse": {
        "required": [
          "referralCode",
          "referralLink",
          "commissionPercent",
          "cookieWindowDays",
          "coupons",
          "payoutsEnabled",
          "stripeOnboarded",
          "postback"
        ],
        "type": "object",
        "properties": {
          "referralCode": {
            "type": "string"
          },
          "referralLink": {
            "type": "string"
          },
          "commissionPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "cookieWindowDays": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "coupons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateCouponDto"
            }
          },
          "payoutsEnabled": {
            "type": "boolean"
          },
          "stripeOnboarded": {
            "type": "boolean"
          },
          "postback": {
            "$ref": "#/components/schemas/AffiliatePostbackDto"
          }
        }
      },
      "AffiliatePayoutDto": {
        "required": [
          "id",
          "createdAtUtc",
          "amountCents",
          "referralCount",
          "status"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "amountCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "referralCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "AffiliatePostbackDto": {
        "required": [
          "url",
          "events"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AffiliatePostbackUpdateRequest": {
        "required": [
          "url",
          "events"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "events": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AffiliateRecruitDto": {
        "required": [
          "joinedAtUtc",
          "status",
          "overrideEarnedCents",
          "overrideSales"
        ],
        "type": "object",
        "properties": {
          "joinedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string"
          },
          "overrideEarnedCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "overrideSales": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "AffiliateRecruitingResponse": {
        "required": [
          "recruitLink",
          "overridePercent",
          "recruits",
          "activeRecruits",
          "overrideEarnings",
          "recentRecruits"
        ],
        "type": "object",
        "properties": {
          "recruitLink": {
            "type": "string"
          },
          "overridePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "recruits": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "activeRecruits": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "overrideEarnings": {
            "$ref": "#/components/schemas/AffiliateEarningsDto"
          },
          "recentRecruits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateRecruitDto"
            }
          }
        }
      },
      "AffiliateReferralDto": {
        "required": [
          "id",
          "createdAtUtc",
          "saleNetCents",
          "couponPercent",
          "commissionPercent",
          "commissionCents",
          "status",
          "maturesAtUtc",
          "subId",
          "campaign"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "saleNetCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "couponPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "uint8"
          },
          "commissionPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "commissionCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "status": {
            "type": "string"
          },
          "maturesAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "subId": {
            "type": [
              "null",
              "string"
            ]
          },
          "campaign": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "AffiliateReferralsResponse": {
        "required": [
          "page",
          "pageSize",
          "total",
          "referrals"
        ],
        "type": "object",
        "properties": {
          "page": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "pageSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "referrals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateReferralDto"
            }
          }
        }
      },
      "AffiliateStatsResponse": {
        "required": [
          "fromUtc",
          "toUtc",
          "clicks",
          "uniqueVisitors",
          "conversions",
          "reversed",
          "conversionRatePercent",
          "epcCents",
          "earnings",
          "groupBy",
          "groups",
          "leads"
        ],
        "type": "object",
        "properties": {
          "fromUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "toUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "clicks": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "uniqueVisitors": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "conversions": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "reversed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "conversionRatePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "epcCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "earnings": {
            "$ref": "#/components/schemas/AffiliateEarningsDto"
          },
          "groupBy": {
            "type": [
              "null",
              "string"
            ]
          },
          "groups": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/AffiliateGroupDto"
            }
          },
          "leads": {
            "$ref": "#/components/schemas/AffiliateLeadsDto"
          }
        }
      },
      "ApiKeyDto": {
        "required": [
          "id",
          "name",
          "keyPrefix",
          "scopes",
          "createdAtUtc",
          "lastUsedAtUtc",
          "revoked"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "keyPrefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "lastUsedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "revoked": {
            "type": "boolean"
          }
        }
      },
      "AuditDto": {
        "required": [
          "id",
          "url",
          "status",
          "runsAllowed",
          "runsUsed",
          "runsRemaining",
          "hasActiveRun",
          "urlLockedAtUtc",
          "expiresAtUtc",
          "createdAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "type": "string"
          },
          "runsAllowed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "runsUsed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "runsRemaining": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "hasActiveRun": {
            "type": "boolean"
          },
          "urlLockedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "expiresAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactRequest": {
        "required": [
          "email",
          "message"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "CreateApiKeyRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CreateApiKeyResponse": {
        "required": [
          "id",
          "name",
          "keyPrefix",
          "key",
          "scopes",
          "notice"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "keyPrefix": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notice": {
            "type": "string"
          }
        }
      },
      "CreateCheckoutRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "CreateCheckoutResponse": {
        "required": [
          "checkoutUrl"
        ],
        "type": "object",
        "properties": {
          "checkoutUrl": {
            "type": "string"
          }
        }
      },
      "CreateOrderRequest": {
        "type": "object",
        "properties": {
          "quantity": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32",
            "default": 1
          },
          "idempotencyKey": {
            "type": [
              "null",
              "string"
            ]
          },
          "dryRun": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "CreateRunRequest": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "CreateRunResponse": {
        "required": [
          "runId",
          "auditId",
          "runNumber",
          "status"
        ],
        "type": "object",
        "properties": {
          "runId": {
            "type": "string",
            "format": "uuid"
          },
          "auditId": {
            "type": "string",
            "format": "uuid"
          },
          "runNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "CreateTargetAnalysisRequest": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "CreateWebhookRequest": {
        "required": [
          "url",
          "description"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "CreateWebhookResponse": {
        "required": [
          "id",
          "url",
          "description",
          "secret",
          "createdAtUtc",
          "note"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "secret": {
            "type": "string"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "LoginWallDto": {
        "required": [
          "verdict",
          "signal",
          "loginUrl"
        ],
        "type": "object",
        "properties": {
          "verdict": {
            "type": "string"
          },
          "signal": {
            "type": [
              "null",
              "string"
            ]
          },
          "loginUrl": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "LoginWallRequest": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          }
        }
      },
      "MeDto": {
        "required": [
          "userId",
          "email",
          "audits"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "audits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditDto"
            }
          }
        }
      },
      "OrderDto": {
        "required": [
          "id",
          "quantity",
          "unitAmountCents",
          "estimatedTotalCents",
          "currency",
          "wholesale",
          "discountPercent",
          "checkoutUrl",
          "status",
          "paymentRoute",
          "failureCode",
          "failureMessage",
          "createdAtUtc",
          "completedAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "quantity": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "unitAmountCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "estimatedTotalCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "currency": {
            "type": "string"
          },
          "wholesale": {
            "type": "boolean"
          },
          "discountPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "checkoutUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "type": "string"
          },
          "paymentRoute": {
            "type": "string"
          },
          "failureCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "failureMessage": {
            "type": [
              "null",
              "string"
            ]
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "completedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        }
      },
      "OrderQuoteDto": {
        "required": [
          "dryRun",
          "quantity",
          "unitAmountCents",
          "estimatedTotalCents",
          "currency",
          "wholesale",
          "discountPercent",
          "paymentRoute",
          "cardBrand",
          "cardLast4",
          "notice"
        ],
        "type": "object",
        "properties": {
          "dryRun": {
            "type": "boolean"
          },
          "quantity": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "unitAmountCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "estimatedTotalCents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "currency": {
            "type": "string"
          },
          "wholesale": {
            "type": "boolean"
          },
          "discountPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "paymentRoute": {
            "type": "string"
          },
          "cardBrand": {
            "type": [
              "null",
              "string"
            ]
          },
          "cardLast4": {
            "type": [
              "null",
              "string"
            ]
          },
          "notice": {
            "type": "string"
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "RunDto": {
        "required": [
          "id",
          "auditId",
          "runNumber",
          "status",
          "queuedAtUtc",
          "startedAtUtc",
          "finishedAtUtc",
          "errorCode",
          "availableReportFormats"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "auditId": {
            "type": "string",
            "format": "uuid"
          },
          "runNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "status": {
            "type": "string"
          },
          "queuedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "startedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "finishedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "errorCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "availableReportFormats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RunEventDto": {
        "required": [
          "type",
          "summary",
          "createdAtUtc"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "summary": {
            "type": [
              "null",
              "string"
            ]
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SaveAccessRequest": {
        "required": [
          "method"
        ],
        "type": "object",
        "properties": {
          "method": {
            "type": "string"
          },
          "url": {
            "type": [
              "null",
              "string"
            ]
          },
          "loginUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "username": {
            "type": [
              "null",
              "string"
            ]
          },
          "password": {
            "type": [
              "null",
              "string"
            ]
          },
          "cookie": {
            "type": [
              "null",
              "string"
            ]
          },
          "signedInCheck": {
            "type": [
              "null",
              "string"
            ]
          },
          "extraHosts": {
            "type": [
              "null",
              "string"
            ]
          },
          "blurScreenshots": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "SaveAccessResponse": {
        "required": [
          "access",
          "check"
        ],
        "type": "object",
        "properties": {
          "access": {
            "$ref": "#/components/schemas/AccessDto"
          },
          "check": {
            "$ref": "#/components/schemas/AccessCheckDto"
          }
        }
      },
      "SubscribeRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          }
        }
      },
      "TargetAnalysisDto": {
        "required": [
          "id",
          "origin",
          "status",
          "stage",
          "urlsSeen",
          "templatesFound",
          "candidatesProbed",
          "sitemapUsed",
          "advisor",
          "failureCode",
          "requestedAtUtc",
          "completedAtUtc",
          "recommendation"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "origin": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "stage": {
            "type": "string"
          },
          "urlsSeen": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "templatesFound": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "candidatesProbed": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "sitemapUsed": {
            "type": "boolean"
          },
          "advisor": {
            "type": "string"
          },
          "failureCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "requestedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "completedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "recommendation": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TargetRecommendationDto"
              }
            ]
          }
        }
      },
      "TargetChoiceDto": {
        "required": [
          "url",
          "templateLabel",
          "templateSharePercent",
          "reason",
          "fieldData",
          "httpStatus",
          "navLinked",
          "whenToPrefer"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "templateLabel": {
            "type": "string"
          },
          "templateSharePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "reason": {
            "type": "string"
          },
          "fieldData": {
            "type": "string"
          },
          "httpStatus": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "navLinked": {
            "type": "boolean"
          },
          "whenToPrefer": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "TargetRecommendationDto": {
        "required": [
          "siteKind",
          "primary",
          "alternates",
          "homepageNote"
        ],
        "type": "object",
        "properties": {
          "siteKind": {
            "type": "string"
          },
          "primary": {
            "$ref": "#/components/schemas/TargetChoiceDto"
          },
          "alternates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TargetChoiceDto"
            }
          },
          "homepageNote": {
            "type": "string"
          }
        }
      },
      "WebhookEndpointDto": {
        "required": [
          "id",
          "url",
          "description",
          "secretPrefix",
          "createdAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "secretPrefix": {
            "type": "string"
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "Your secret key, formatted `psa_live_…`. Send it in the **`X-Api-Key`** header on every request, from your server — never from browser code. Create and revoke keys from your dashboard; the secret is shown only once at creation. Each key carries scopes: `read`, `run`, and — only when asked for explicitly — `purchase`.",
        "name": "X-Api-Key",
        "in": "header"
      },
      "DashboardSession": {
        "type": "apiKey",
        "description": "The signed-in dashboard session (an HttpOnly cookie set by /account/login). Only API-key management uses it, and only a browser has it: it cannot be typed into a client. An API key sent to these operations is answered with `403 dashboard_session_required`.",
        "name": "__Host-psa.auth",
        "in": "cookie"
      }
    }
  },
  "tags": [
    {
      "name": "Checkout",
      "description": "The anonymous purchase route: start a hosted Stripe Checkout for the one-time audit purchase and send the buyer to it. No authentication. An authenticated account orders with `POST /orders` instead."
    },
    {
      "name": "Contact",
      "description": "Contact intake for integrations. Authenticated — an API key or the dashboard session — because every message is classified; the website's own contact form uses a separate, spam-challenged route. Website plumbing, not part of the audit integration."
    },
    {
      "name": "Referral links",
      "description": "The affiliate's public links — the referral redirect that sets the attribution cookie, and the direct-checkout link that carries attribution on the Stripe session itself. Anonymous by design: visitors follow them; nothing here is called with a key."
    },
    {
      "name": "Affiliate",
      "description": "The affiliate's own reporting API: profile and links, traffic and earnings, conversions, payouts, recruiting, and the server-to-server postback. Scoped strictly to the authenticated account; an account without an active affiliate profile gets `403 not_an_affiliate`."
    },
    {
      "name": "Audits",
      "description": "Your audit entitlements and runs — the core integration surface. One entitlement is 1 URL, 3 runs (1 + 2 re-runs), valid 30 days from the first run. Authenticated with an API key carrying `read` (and `run` to start a run)."
    },
    {
      "name": "Signed-in audits"
    },
    {
      "name": "Target Finder",
      "description": "Not sure which URL to audit? Analyzes your site (robots → sitemap → homepage, URL templates, candidate probes, Google CrUX field-data checks) and recommends the page whose audit fixes the most, with alternates. Available while an audit's URL is still unlocked. Creating an analysis needs the `run` scope."
    },
    {
      "name": "API keys",
      "description": "Manage the keys that authenticate API requests. **Dashboard session only**: these operations authenticate with the signed-in browser session and answer `403 dashboard_session_required` to an API key, so a key can never mint or revoke keys. Create keys at /account/api-keys."
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Orders",
      "description": "Buy audit credits on the account. **Production: may charge a saved card.** Start with `dryRun: true` — a quote that creates nothing — then order with an `Idempotency-Key`. Requires an API key created with the `purchase` scope, which is never implicit; a signed-in browser session is refused (`403 api_key_required`), so this console cannot order on a session alone. An approved reseller's wholesale price is applied automatically, server-side. With no saved card the response is a Stripe Checkout URL to pay in a browser; with a saved card and mandate the card is charged immediately."
    },
    {
      "name": "Newsletter",
      "description": "Double-opt-in newsletter subscription. Website plumbing, not part of the audit integration. No authentication."
    }
  ],
  "externalDocs": {
    "description": "Developer portal: quickstart, lifecycle diagrams, the findings schema and the error catalog",
    "url": "https://pagespeedaudit.com/docs"
  }
}