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

# Introduction

> Base URL, API tokens, request and response conventions, error codes and rate limits for the Pharus SBOM API.

<Info>
  **Plans:** Every plan. While the workspace is read-only, uploads are refused with 402. **Who:** owners and admins create and revoke API tokens; every member can see the token list.
</Info>

The Pharus API takes SBOMs from your CI pipelines and from Dependency-Track. Each request is authenticated with an API token that belongs to one product family, and each SBOM you send is stored for that family and matched within seconds.

## Base URL

All endpoints are under [https://app.pharussecurity.com/api/v1](https://app.pharussecurity.com/api/v1) and use HTTPS.

| Endpoint | What it does |
| - | - |
| `POST /api/v1/sboms` | Upload one SBOM. See [upload an SBOM](/api-reference/sboms). |
| `POST /api/v1/connectors/dependency-track` | Receive Dependency-Track's `BOM_PROCESSED` notifications. See [Dependency-Track](/api-reference/dependency-track). |

## Authentication

Send the token in the `Authorization` header:

```http theme={null}
Authorization: Bearer phr_...
```

A token:

* starts with `phr_`, followed by 43 letters, digits, `-` and `_`, so secret scanners can recognise it;
* can upload SBOMs to one product family and nothing else;
* is shown once, when it is created. Pharus stores only a hash, so a lost token has to be replaced.

Never put a token in a URL. Store it as a secret in your CI system, for example as `PHARUS_TOKEN`.

### Create a token

<Steps>
  <Step title="Open the token page">
    Go to **Settings → API tokens** and select **Create token**. You need at least one product family.
  </Step>

  <Step title="Describe the token">
    Enter a **Name**, after the pipeline that uses it, for example "GitHub Actions – gateway-g3". Pick the **Product family** and when it **Expires**: **In 30 days**, **In 90 days**, **In 1 year** (the default) or **Never**.
  </Step>

  <Step title="Copy it">
    Select **Create token**. Pharus shows the token once, under **Copy your token**: copy it and add it to your pipeline as a secret. **Open pipeline snippets** takes you to ready-made steps on the **SBOMs** page.
  </Step>
</Steps>

Create one token per pipeline, so you can revoke a single CI job without touching the others. The token's name shows on each SBOM it sends, under **Sent by**, and in the audit trail.

The list under **Settings → API tokens** shows each token's **Name**, **Product family**, the first characters of the **Token**, when it was **Created** and by whom, when it was **Last used**, when it **Expires** and its **Status**: **Active**, **Expired** or **Revoked**.

### Revoke or rotate a token

To revoke a token, select **Revoke token** on its row and confirm. Pipelines using it get 401 from then on. This can't be undone.

To rotate a token, create a new one for the same family, replace the secret in your pipeline, check that the new token's **Last used** changes, then revoke the old one.

A token also stops working when it expires, and while its product family is archived. Archived families' tokens leave the list; they work again if the family is restored, unless they have expired or been revoked meanwhile.

## Requests

* Send `POST` requests over HTTPS.
* The body is the SBOM file itself, not a form upload and not wrapped in JSON. With curl, use `--data-binary`.
* Gzip the body and send `Content-Encoding: gzip`. A request may be at most 4 MB as sent, and 50 MB once decompressed.
* Optional `X-Pharus-*` headers add the product version and pipeline details. See [upload an SBOM](/api-reference/sboms).

## Responses

Responses are JSON. A successful upload returns `202 Accepted` for a new SBOM and `200 OK` when Pharus already has the same file for that family, so a retry is safe.

Errors have this shape:

```json theme={null}
{
  "error": "unsupported_format",
  "message": "Unsupported SBOM format. Send CycloneDX JSON 1.4–1.7 or SPDX JSON 2.2–2.3.",
  "detail": "CycloneDX 1.3"
}
```

`error` is a stable code you can test for. `message` is an English explanation for your CI log. `detail` is only there when Pharus has more to say.

## Status codes

| Status | `error` | Meaning |
| - | - | - |
| 200 | | The same SBOM was sent before; nothing new was stored |
| 202 | | The SBOM was stored; matching has started |
| 400 | `invalid_json`, `invalid_sbom`, `empty`, `bad_encoding` | The body can't be read |
| 401 | `unauthorized` | The token is missing, invalid, revoked or expired, or its product family is archived |
| 402 | `billing_lapsed` | The workspace is read-only, so nothing was stored |
| 404 | `family_not_found` | The token's product family is no longer available |
| 413 | `too_large` | More than 4 MB as sent, or 50 MB decompressed |
| 415 | `xml_unsupported`, `unsupported_format` | Not CycloneDX JSON 1.4–1.7 or SPDX JSON 2.2–2.3 |
| 422 | `too_many_components` | More than 50 000 components |
| 429 | `rate_limited` | Too many requests for this token; see below |
| 500 | `internal` | Something went wrong on Pharus' side. Try again. |

The Dependency-Track endpoint has a few codes of its own. See [Dependency-Track](/api-reference/dependency-track#responses).

### 402 when the workspace is read-only

When the free trial or the subscription ends without a new one, the workspace moves to Free and becomes read-only. When the owners close it, it is closed. In both cases every upload gets `402` with `billing_lapsed`, and the message says which: a Free workspace needs an owner to subscribe under **Settings → Billing**, and a closed one needs an owner to reopen it in company settings.

A 402 makes a CI step that uses `curl --fail-with-body` fail visibly, instead of the SBOM being dropped without a trace. See [billing](/workspace/billing).

## Rate limits

Each token can make 60 requests per hour, counted together across `POST /api/v1/sboms` and the Dependency-Track endpoint. Every authenticated request counts, whether or not it stores anything: duplicates, rejected files and Dependency-Track test notifications too.

Past the limit, Pharus answers `429` with `rate_limited` and a `Retry-After` header with the number of seconds to wait.

## Related

<CardGroup cols={2}>
  <Card title="Upload an SBOM" icon="upload" href="/api-reference/sboms" />

  <Card title="Dependency-Track" icon="webhook" href="/api-reference/dependency-track" />

  <Card title="GitHub Actions" icon="git-branch" href="/api-reference/ci/github-actions" />

  <Card title="SBOMs in the app" icon="package" href="/monitoring/sboms" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.