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

# REST API

> List, search, create, update, and delete tenant resources through the versioned JSON API.

The REST API is available under `$SILO_API_URL/v1`. Requests and responses use
JSON unless an endpoint says otherwise. Use the live OpenAPI 3.1 document at
`$SILO_API_URL/v1/openapi` as the source of truth for request and response
schemas.

## Resource routes

| Resource        | Collection route                    | Search route                               |
| --------------- | ----------------------------------- | ------------------------------------------ |
| Articles        | `/v1/sites/{siteId}/articles`       | `/v1/sites/{siteId}/articles/search`       |
| Books           | `/v1/books`                         | `/v1/books/search`                         |
| Magazines       | `/v1/magazines`                     | `/v1/magazines/search`                     |
| Issues          | `/v1/magazines/{magazineId}/issues` | `/v1/magazines/{magazineId}/issues/search` |
| Knowledge files | `/v1/knowledge-files`               | `/v1/knowledge-files/search`               |
| CRM contacts    | `/v1/crm/contacts`                  | `/v1/crm/contacts/search`                  |
| CRM companies   | `/v1/crm/companies`                 | `/v1/crm/companies/search`                 |

Collection routes support `GET` and `POST`. Append the resource ID to use
`GET`, `PATCH`, or `DELETE` on one record. Article item routes also include the
site ID, and issue item routes also include the magazine ID.

## List records

List endpoints accept:

* `limit`: maximum records to return
* `cursor`: opaque cursor from the preceding response
* `search`: optional case-insensitive text filter

Do not inspect or construct cursors. Pass `pageInfo.nextCursor` unchanged in
the next request.

```bash theme={"system"}
curl --get "$SILO_API_URL/v1/crm/contacts" \
  --header "Authorization: Bearer $SILO_ACCESS_TOKEN" \
  --data-urlencode "limit=20" \
  --data-urlencode "search=lovelace"
```

## Search records

Search routes accept a required `query` and an optional `limit`. Search for
books, magazines, issues, CRM records, and knowledge files also supports an
opaque `cursor` where advertised by OpenAPI.

Article search returns article and CMS taxonomy sources within one site.
Knowledge search searches content visible to the authenticated user, not files
from other organizations or private files the user cannot access.

```bash theme={"system"}
curl --get "$SILO_API_URL/v1/sites/$SITE_ID/articles/search" \
  --header "Authorization: Bearer $SILO_ACCESS_TOKEN" \
  --data-urlencode "query=quarterly grain report" \
  --data-urlencode "limit=10"
```

## Create an article draft

Article writes accept structured article-level fields and version-level
fields. A public API create produces a draft.

```bash theme={"system"}
curl "$SILO_API_URL/v1/sites/$SITE_ID/articles" \
  --request POST \
  --header "Authorization: Bearer $SILO_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: article-2026-07-10-001" \
  --data '{
    "articleData": {
      "allowComments": true,
      "categoryIds": ["category-id"]
    },
    "versionData": {
      "title": "Quarterly grain report",
      "summary": "Current market movements and outlook.",
      "status": "DRAFT"
    }
  }'
```

Use `PATCH` for partial updates. At least one supported field must be present.
Unknown fields are rejected instead of being silently ignored.

## Write behavior

Every create, update, and delete request:

* verifies the token's organization, user, client, resource, and scope
* checks current Silo module and resource permissions
* verifies that referenced resources belong to the authorized tenant
* enters the same transaction and outbox pipeline used by Silo Admin
* emits normal downstream updates only after the database transaction commits

Use an `Idempotency-Key` on all writes so a timeout can be retried without
duplicating the operation. See [Errors and idempotency](/api-reference/errors-idempotency).
