# How to query (search) structured content records via the Content API

Source: https://dev.arcxp.com/custom-content/how-to-guides/how-to-query-search-structured-content-records-via-the-content-api/

The Content API exposes SCT records through three read-only endpoints: one for listing records by schema type, one for fetching a single record by ID, and one for fetching a single record by URL. This is the read path for headless and hybrid implementations. Think server-rendered sites, mobile apps, or any client that fetches structured content outside of PageBuilder.

For the PageBuilder content source approach, see [How to Embed Structured Content Records in PageBuilder](https://dev.arcxp.com/custom-content/how-to-guides/how-to-embed-structured-content-records-in-pagebuilder/).

## Before you start

You need:

- Your Arc XP organization ID (`org`)
- A bearer token with Content API read access
- A schema with at least one published record
- The schema `name` (e.g., `events`). This is the identifier from the schema definition, not its display name

Records only appear in the Content API after they are published and circulated to a website. A query only returns records circulated to the `website` you pass. Draft records stay in the Draft API.

## How records appear in responses

A Content API response for an SCT record includes two parts: server-assigned metadata and the field values from your schema.

```json
{
  "document_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "schema_name": "events",
  "created_date": "2026-05-01T14:30:00Z",
  "first_publish_date": "2026-05-02T10:00:00Z",
  "publish_date": "2026-06-10T09:15:00Z",
  "websites": {
    "the-daily-planet": { "website_url": "/events/arc-xp-summit-2026/" }
  },
  "schema_content": {
    "title": "Arc XP Summit 2026",
    "event-date": "2026-09-15T09:00:00Z",
    "location": {
      "lat": 38.9072,
      "lon": -77.0369
    },
    "ticket-url": "https://example.com/tickets"
  }
}
```

The `schema_content` object contains the field values defined in your schema. Optional fields that were never given a value are absent.

## Records with references

A schema can declare `reference` fields (see [Reference fields](https://dev.arcxp.com/custom-content/reference/structured-content-field-types#reference-fields)). In the Content API the reference is already resolved: the field holds the referenced document in Arc XP Native Specification (ANS) format, not a pointer, so a record and the content it points at arrive in one response.

```json
{
  "document_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "schema_name": "events",
  "schema_content": {
    "title": "Arc XP Summit 2026",
    "venue": {
      "_id": "PLVVMP6DQZDQ3EU3LZ7HKQZCJE",
      "type": "schema",
      "schema_name": "venues",
      "schema_content": { "name": "Walter E. Washington Convention Center", "city": "Washington" }
    },
    "hero_image": {
      "_id": "4XK6OWIZNNF3RKKBYWT7ZY5QZQ",
      "type": "image",
      "url": "https://cloudfront-us-east-1.images.arcpublishing.com/…/summit.jpg",
      "caption": "Opening keynote"
    }
  }
}
```

What to expect:

- **One level deep.** A reference inside a resolved target (the venue’s own `city` reference, say) is left as it was stored, a node shaped `{"type": "reference", "referent": {…}}`. Fetch it separately if you need it.
- **Unresolved references stay as nodes.** If the target does not exist, has been deleted, or has no published copy yet, the field keeps that same `reference` node instead of the content. Check `type === "reference"` before reading a field as content.
- **The copy is as of the record’s last publish.** Content API serves what was resolved when the referencing record was indexed. When the target changes, the record shows the new version only after it is republished.
- **Reference fields are not queryable.** They take no index, so `q=` cannot filter on anything inside a resolved reference. Put the values you need to search on in indexed fields of the record itself.

## Fetch a list of records

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}" \
  --data-urlencode "size=25" \
  --data-urlencode "page=1"
```

Replace `{org}` with your organization ID and `{your-site}` with your site identifier.

The response wraps the current page of records in `data`:

```json
{
  "data": [
    { ... },
    { ... }
  ]
}
```

If no record matches, the API returns a 404.

**Query parameters:**

| Parameter         | Type    | Description                                                                                                      |
| ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| schema\_name      | string  | Required. Schema identifier (e.g., events).                                                                      |
| website           | string  | Required. Your site identifier.                                                                                  |
| size              | integer | Records per page. Default 25, max 50.                                                                            |
| page              | integer | Page number, from 1 to 100.                                                                                      |
| sort              | string  | first\_publish\_date:desc (default) or publish\_date:desc.                                                       |
| q                 | string  | Structured filter expression: field:value pairs, whitespace-separated, implicit AND. Not a free-text search box. |
| include / exclude | string  | Comma-separated list of fields to return or omit (e.g. schema\_content.title). Use one or the other.             |

## Fetch a single record by ID

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/by-id/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}"
```

Returns the record in `data` as a single object. You get a 404 if the record does not exist, hasn’t been published yet, or isn’t circulated to the website.

## Fetch a single record by URL

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/by-url/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "url=/events/arc-xp-summit-2026/" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}"
```

Returns the record circulated at that URL on the website.

## Filtering with indexed fields

Only fields with a `search_settings.retrieval` array set in the schema can be used in `q`.

`q` is a structured filter expression: `field:value` pairs, whitespace-separated, implicit AND. That supports equality, range, and geo-distance queries against any field with `search_settings.retrieval` set:

- String equality: `schema_content.category:"music"`
- Number or boolean equality: `schema_content.paid:true`
- Range, inclusive: `schema_content.event_date:[2026-07-11 TO 2026-07-13]`
- Range, exclusive: `schema_content.venue_capacity:{100 TO 500}`
- Open-ended range: `schema_content.event_date:[2026-07-11 TO *]`
- Geo distance: `schema_content.location_geo:33.77,-84.37,8km`

Valid `retrieval` index kinds: `keyword`, `geo`, `range`. Which kind is valid depends on the field’s `type`; see [Developer Guide](https://dev.arcxp.com/custom-content/core-concepts/developer-guide/) for the full type-to-kind table. Range syntax only works on a field whose `retrieval` array is `["range"]`.

To see which fields are indexed, fetch your schema definition:

Terminal window

```bash
curl "https://api.{org}.arcpublishing.com/draft/v1/schema-type/events" \
  -H "Authorization: Bearer {your-token}"
```

Any field with a `search_settings.retrieval` array is queryable via the Content API. A field with only `search_settings.editorial` set is searchable in Data Manager but invisible to this API.

> **Plan indexed fields before writing data:**
>
> Adding search indexing to a field is allowed at any time. Removing or changing it is a breaking change.

## Examples

### Fetch the latest events

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}" \
  --data-urlencode "sort=publish_date:desc" \
  --data-urlencode "size=10"
```

Returns the 10 most recently published events.

### Filter events by category

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}" \
  --data-urlencode 'q=schema_content.category:"music"' \
  --data-urlencode "size=10"
```

Filters to records where `category` equals `"music"`. Requires `category` to have `search_settings: { "retrieval": ["keyword"] }` in the schema.

### Combine filters

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}" \
  --data-urlencode 'q=schema_content.category:"music" schema_content.event_date:[2026-07-11 TO *]'
```

Returns music events from July 11, 2026 onward. Requires `event_date` to have `search_settings: { "retrieval": ["range"] }` in the schema.

### Fetch a specific record

Get the `document_id` from a list response, or store it when the record is created via the Draft API.

Terminal window

```bash
curl -G "https://api.{org}.arcpublishing.com/content/v5/search/schemas/by-id/" \
  -H "Authorization: Bearer {your-token}" \
  --data-urlencode "id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  --data-urlencode "schema_name=events" \
  --data-urlencode "website={your-site}"
```

## Pagination

Use `size` (up to 50) and `page` (up to 100) to walk through results.

```
# Page 1
?schema_name=events&website=my-site&size=50&page=1

# Page 2
?schema_name=events&website=my-site&size=50&page=2
```

A page past the last result returns a 404.
