> ## Documentation Index
> Fetch the complete documentation index at: https://docs.37audits.com/llms.txt
> Use this file to discover all available pages before exploring further.

# REST API

> Read and write your 37 Audits organizations, projects, and monitored URLs over HTTP

<Info>
  **REST API** — the same read/write path the [37audits.com](https://www.37audits.com) website uses for organizations, projects, monitored URLs, and project software, plus a read-only view of audit results and the auditor catalog, and an endpoint to trigger a fresh audit run.
</Info>

<CardGroup cols={2}>
  <Card title="One data layer" icon="database">
    The REST API, the [MCP server](/mcp-server), and the website share the same authorization and data layer — a caller only ever sees organizations they belong to.
  </Card>

  <Card title="Mostly read/write" icon="pencil">
    Organizations, projects, monitored URLs, and project software are full CRUD. Audit results, findings, and the auditor catalog are read-only — they're written by the background auditor pipeline, not through this API.
  </Card>
</CardGroup>

## Base URL

```
https://api.37audits.com/v2
```

Every path below is relative to that base. An interactive OpenAPI explorer is published alongside the API at `https://api.37audits.com/swagger-ui.html`.

## Authentication

The API accepts two credential types on the same endpoints, sent as an `Authorization: Bearer <token>` header or an `x-api-key` header:

### Bearer token (website sessions)

The same Supabase access token used to sign in to [37audits.com](https://www.37audits.com). The API verifies it as an ES256 JWT against Supabase's JWKS endpoint. This is what the website itself sends, and what an MCP client obtains via the [OAuth flow](/mcp-server#authentication).

### API key (programmatic access)

For scripts and server-to-server calls, create a key at **`https://www.37audits.com/organizations/{orgSlug}/api-keys`** — organization admins only — and send it as `x-api-key` instead of a bearer token. The key identifies the user who created it and is scoped to one organization and role. The raw key is shown once, at creation time, prefixed `tsa_live_` copy it then, it can't be retrieved again.

The same operation is available as `POST /organizations/{organizationId}/api-keys` (see below) if you'd rather script key creation than use the page.

## Errors

Failures are returned as [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) `application/problem+json` bodies:

```json theme={"dark"}
{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "Project not found"
}
```

| Status                 | Meaning                                                                                                                                |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Unauthorized`     | Missing or invalid credentials.                                                                                                        |
| `402 Payment Required` | `run` was called but the organization doesn't have enough credits for the resolved auditor(s).                                         |
| `403 Forbidden`        | The resource is visible to the caller, but only owners/admins can write to it (see below).                                             |
| `404 Not Found`        | The id or slug doesn't exist, or isn't visible to the caller — an inaccessible resource looks identical to a missing one, never `403`. |

Any organization member can **read** projects, monitored URLs, project software, audit results, and the auditor catalog. Only organization owners/admins can **create, update, or delete** projects, monitored URLs, and project software — a member without that role gets `403` on write, since the resource is already visible to them (unlike a non-member, who gets `404`). Audit results and findings have no write path at all, for anyone.

## Organizations

| Method & path                   | Description                                                     |
| ------------------------------- | --------------------------------------------------------------- |
| `GET /organizations`            | Organizations the caller belongs to.                            |
| `GET /organizations/{idOrSlug}` | One organization, by UUID or slug.                              |
| `POST /organizations`           | Create an organization. Body: `name` (required), `description`. |
| `PATCH /organizations/{id}`     | Update `name` and/or `description`.                             |
| `DELETE /organizations/{id}`    | Delete an organization.                                         |

## API keys

| Method & path                                          | Description                                                                                       |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `GET /organizations/{organizationId}/api-keys`         | List an organization's API keys.                                                                  |
| `POST /organizations/{organizationId}/api-keys`        | Create a key. Body: `name` (required), `role`. Admins only. Response includes the raw `key` once. |
| `DELETE /organizations/{organizationId}/api-keys/{id}` | Revoke a key.                                                                                     |

<Tip>
  Most users don't need this endpoint directly — create and revoke keys from **`https://www.37audits.com/organizations/{orgSlug}/api-keys`** instead.
</Tip>

## Projects

| Method & path                                | Description                                                                   |
| -------------------------------------------- | ----------------------------------------------------------------------------- |
| `GET /organizations/{orgIdOrSlug}/projects`  | List projects in an organization.                                             |
| `POST /organizations/{orgIdOrSlug}/projects` | Create a project. Body: `name` (required), `description`. Owners/admins only. |
| `GET /projects/{id}`                         | Get a project by id.                                                          |
| `PATCH /projects/{id}`                       | Update `name` and/or `description`. Owners/admins only.                       |
| `DELETE /projects/{id}`                      | Delete a project. Owners/admins only.                                         |

## Monitored URLs

| Method & path                               | Description                                                                                                                                                   |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /projects/{projectId}/monitored-urls`  | List monitored URLs in a project.                                                                                                                             |
| `POST /projects/{projectId}/monitored-urls` | Add a monitored URL. Body: `url` (required, `http(s)://…`), `label`, `status`, `checkInterval`, `basicAuthUsername`, `basicAuthPassword`. Owners/admins only. |
| `GET /monitored-urls/{id}`                  | Get a monitored URL by id.                                                                                                                                    |
| `PATCH /monitored-urls/{id}`                | Update `label`, `status`, `checkInterval`, or basic-auth credentials. Owners/admins only.                                                                     |
| `DELETE /monitored-urls/{id}`               | Delete a monitored URL. Owners/admins only.                                                                                                                   |

`status` is one of `draft`, `active`, `disabled`. Basic-auth credentials are write-only: settable on create/update, never returned in a response — a `hasBasicAuth` boolean on the response indicates whether they're set.

## Project software

| Method & path                          | Description                                                                                                       |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `GET /projects/{projectId}/softwares`  | List software/tech-stack entries for a project.                                                                   |
| `POST /projects/{projectId}/softwares` | Add a software entry. Body: `vendor`, `product` (required), `version` (required), `category`. Owners/admins only. |
| `GET /project-softwares/{id}`          | Get a software entry by id.                                                                                       |
| `PATCH /project-softwares/{id}`        | Update `vendor`, `product`, `version`, and/or `category`. Owners/admins only.                                     |
| `DELETE /project-softwares/{id}`       | Delete a software entry. Owners/admins only.                                                                      |

## Auditors

| Method & path        | Description                                                                        |
| -------------------- | ---------------------------------------------------------------------------------- |
| `GET /auditors`      | List active auditors in the catalog. An inactive auditor is invisible, even by id. |
| `GET /auditors/{id}` | Get one active auditor.                                                            |

## Audit results

Read-only end to end — these rows are written by the background auditor pipeline (or by `run`, below), never through a create/update/delete call.

| Method & path                               | Description                                                                                                        |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `GET /monitored-urls/{urlId}/audit-results` | Paginated audit runs for a monitored URL, newest first. Query params: `page` (default `0`), `size` (default `20`). |
| `GET /audit-results/{id}`                   | Get one audit run.                                                                                                 |
| `GET /audit-results/{id}/checks`            | List the individual findings belonging to one audit run.                                                           |
| `GET /check-results/{id}`                   | Get one finding.                                                                                                   |

## Running audits

| Method & path                                    | Description                                                                                                |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `POST /monitored-urls/{urlId}/audit-results/run` | Runs every active auditor against the URL, or just one via `?auditorId=`, and returns the created results. |

This is the one write path into audit results, and the only billable call in the API — it's the same "run all auditors" action the website triggers client-side, just server-side. It pre-flight-checks the resolved auditor(s)' cost against the organization's credit balance and returns `402 Payment Required` if insufficient; credits are deducted only for auditors that actually complete, so a failed auditor isn't charged. Any organization member can trigger a run — unlike the other write paths above, it isn't restricted to owners/admins. The equivalent MCP tool is [`run_audits`](/mcp-server#running-audits).
