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

# API Overview

> Base URL, authentication, pagination, rate limiting, and API guarantees.

## Base URL

```
https://api.artifacta.io
```

All endpoints (except `GET /health`) are prefixed with `/v1/`.

## Authentication

Every request requires a Bearer token:

```bash theme={null}
Authorization: Bearer ak_live_<key>
```

Get your key from [app.artifacta.io/dashboard/keys](https://app.artifacta.io/dashboard/keys). Use `GET /v1/whoami` to verify your key.

## Endpoints

### Artifacts

| Method   | Endpoint                                               | Description                 |
| -------- | ------------------------------------------------------ | --------------------------- |
| `POST`   | [`/v1/artifacts`](/api/upload-artifact)                | Upload an artifact          |
| `GET`    | [`/v1/artifacts`](/api/list-artifacts)                 | List artifacts with filters |
| `GET`    | [`/v1/artifacts/{id}`](/api/get-artifact)              | Get artifact metadata       |
| `GET`    | [`/v1/artifacts/{id}/download-url`](/api/download-url) | Get presigned download URL  |
| `DELETE` | [`/v1/artifacts/{id}`](/api/delete-artifact)           | Soft-delete an artifact     |
| `POST`   | [`/v1/artifacts/{id}/links`](/api/create-link)         | Create a download link      |

### Presigned uploads

| Method | Endpoint                                              | Description                            |
| ------ | ----------------------------------------------------- | -------------------------------------- |
| `POST` | [`/v1/artifacts/upload-url`](/api/presigned-upload)   | Get presigned upload URL (large files) |
| `POST` | [`/v1/artifacts/{id}/complete`](/api/complete-upload) | Finalize presigned upload              |

### Artifact Pages (authenticated)

| Method   | Endpoint                                                | Description                                         |
| -------- | ------------------------------------------------------- | --------------------------------------------------- |
| `POST`   | [`/v1/artifacts/{id}/publish`](/api/publish-artifact)   | Publish an artifact as a public page                |
| `DELETE` | [`/v1/artifacts/{id}/publish`](/api/unpublish-artifact) | Unpublish a page (accepts artifact ID or page slug) |

### Artifact Pages (public — no auth)

| Method | Endpoint                                              | Description                              |
| ------ | ----------------------------------------------------- | ---------------------------------------- |
| `GET`  | [`/v1/public/pages/{slug}/gate-info`](/api/gate-info) | Check if a page is password-protected    |
| `POST` | [`/v1/public/pages/{slug}/unlock`](/api/unlock-page)  | Verify passcode, receive a content token |
| `POST` | [`/v1/public/pages/{slug}/report`](/api/report-page)  | Submit an abuse report (always 202)      |

<Info>
  The three `/v1/public/pages/` endpoints require **no Bearer token**. They are called by the public viewer and by end users' browsers. The "Every request requires a Bearer token" rule applies only to authenticated endpoints.
</Info>

### Sessions

| Method | Endpoint                                      | Description    |
| ------ | --------------------------------------------- | -------------- |
| `POST` | [`/v1/sessions/{id}/seal`](/api/seal-session) | Seal a session |

### Account

| Method | Endpoint                    | Description                  |
| ------ | --------------------------- | ---------------------------- |
| `GET`  | [`/v1/whoami`](/api/whoami) | Verify auth, get tenant info |
| `GET`  | [`/health`](/api/health)    | Health check (no auth)       |

## Content upload paths

| Method                                          | Best for                            | Size limit    |
| ----------------------------------------------- | ----------------------------------- | ------------- |
| Multipart form data (`POST /v1/artifacts`)      | CLI, file uploads                   | 500 MB        |
| JSON body with base64 (`POST /v1/artifacts`)    | Programmatic callers, small content | 10 MB decoded |
| Presigned URL (`upload-url` → PUT → `complete`) | Large files                         | 5 GB          |

## Pagination

All list endpoints use **cursor-based pagination**.

* Response includes `next_cursor` (`null` if no more results)
* Pass `cursor=<value>` for the next page
* Max `limit`: 200, default: 50

<Info>
  **Sort order guarantee:** Results are always ordered by `created_at DESC, artifact_id DESC`. This is a V1 API contract and will not change without a new API version.
</Info>

## Rate limiting

Per-tenant: **100 requests/second sustained, 200 requests/second burst** (sliding window).

**Headers on every response:**

| Header                  | Description                       |
| ----------------------- | --------------------------------- |
| `X-RateLimit-Limit`     | Requests per second allowed       |
| `X-RateLimit-Remaining` | Remaining in current window       |
| `X-RateLimit-Reset`     | Unix timestamp when window resets |

When exceeded: `429 Too Many Requests` with `Retry-After` header and `retry_after_seconds` in the body.

## Error response shape

All errors return:

```json theme={null}
{
  "error": {
    "code": "artifact_not_found",
    "message": "Artifact art_xxx was not found.",
    "status": 404
  }
}
```

Match on `error.code` (stable). Never parse `error.message`. See the [full error reference](/errors).

## The `page` field on artifact responses

`GET /v1/artifacts/{id}` includes a `page` sub-object when the artifact has a live published page:

```json theme={null}
{
  "artifact_id": "art_abc123",
  "filename": "report.pdf",
  "page": {
    "public_url": "https://artifacta.io/a/pg_aB3xK9mP1qR5sT2u",
    "visibility": "unlisted"
  }
}
```

| Field             | Type   | Description                                                  |
| ----------------- | ------ | ------------------------------------------------------------ |
| `page.public_url` | string | Full viewer URL. Anyone with this URL can view the artifact. |
| `page.visibility` | string | `"unlisted"` or `"public"`.                                  |

`page` is `null` when no live page exists (never published, or unpublished). It is present only on the single-artifact `GET /v1/artifacts/{id}` response — list results always return `page: null`.

## API guarantees

* **Read-after-write consistency:** An artifact written via `POST /v1/artifacts` is immediately visible to all read endpoints.
* **Backward compatibility:** Additive changes (new fields, new optional parameters, new endpoints) are non-breaking. Removals and type changes require a new API version. V1 remains available for 12 months after V2 launches.

<Note>
  **Coming in V1.1:** `POST /v1/artifacts/batch/download-urls` — batch download URLs for up to 20 artifacts in a single request.
</Note>
