# Filter Files

Returns a paginated collection of the tenant's non-image files (documents, spreadsheets, archives, …),
filtered and sorted using OData query options (`$filter`, `$orderby`, `$top`, `$skip`).
## Authentication
Requires a valid API key in the `X-API-KEY` header.
## Response (200 OK)
The page is wrapped in the house collection envelope — the files are under `value`, never at the
top level:

```json
{
  "value": [
    {
      "reference": "product-datasheet.pdf",
      "numLinks": 3,
      "status": "Ok",
      "modifiedOn": "2024-04-05T08:44:33",
      "fileType": "pdf",
      "createdOn": "2024-04-05T08:44:33",
      "tags": ["datasheets", "catalog"],
      "url": "https://cdn.example.com/product-datasheet.pdf",
      "sizeInBytes": 102400
    }
  ],
  "@count": 137,
  "@readLink": "https://api2.saleslayer.com/dam/files?$top=50",
  "@nextLink": "https://api2.saleslayer.com/dam/files?$top=50&$skip=50"
}
```
Notes on the payload:
- `status` tells you whether the file is usable yet — see the status values below.
- `url` and `sizeInBytes` come from the stored metadata and are empty / `0` until processing has
recorded them.
- `tags` is stored as a comma-separated string, so a tag that itself contains a comma comes back
split into several tags.
- `@count` is the total number of matches, ignoring `$top`/`$skip`.
- `@readLink` is the canonical URL of this collection — this request, echoed back.
- `@nextLink` is the URL of the next page and is omitted on the last page.

The `@`-prefixed hypermedia links (`@readLink`, `@nextLink`) are only emitted when hypermedia
enrichment is configured for the deployment; `@count` is always present. Where the links are
absent, page forward by incrementing `$skip` yourself until fewer than `$top` items come back.
## Supported fields
Only these fields can be used in `$filter` and `$orderby`:
`reference`, `numLinks`, `status`, `modifiedOn`, `fileType`, `createdOn`
Field names are case-insensitive. Every other field — including `tags`, `url` and
`sizeInBytes` — is **not** queryable: naming one in `$filter` or `$orderby` returns 400.
`$orderby` honours only the first sort expression.
`$select` and `$expand` are not supported and are ignored.
## Supported operators and functions
- Comparison: `eq`, `ne`, `gt`, `ge`, `lt`, `le`
- Logical: `and`, `or`, `not`
- Sets: `in`
- Functions: `contains`, `startswith`, `endswith`

## Status field values
- `Vd` - Void (not yet started processing)
- `Up` - Updating (being uploaded/updated)
- `Ok` - Processed correctly (ready to use)
- `Re` - Reprocessing
- `Er` - Error (processing failed)
- `Dv` - Deleted/void

Results are not filtered by status, so files in any of these states can be returned. Filter on
`status` explicitly if you only want usable files.
## Examples

```
GET /files?$filter=fileType eq 'pdf'
GET /files?$filter=status eq 'Ok'
GET /files?$filter=fileType eq 'csv' and status eq 'Ok'
GET /files?$filter=status in ('Ok', 'Re')
GET /files?$filter=contains(reference, 'datasheet')
GET /files?$filter=startswith(reference, 'product-') and numLinks gt 0
GET /files?$orderby=createdOn desc
GET /files?$filter=fileType ne 'txt'&$orderby=numLinks desc&$skip=0&$top=50
```
## Error Responses
- **400 Bad Request**: Invalid `$filter` syntax, a field that is not queryable in `$filter` or
`$orderby`, a negative `$skip`, or a `$top` that is not between 1 and 100
- **401 Unauthorized**: Missing or invalid API key. Returned by the API gateway as
`{ "message": "Unauthorized", "request_id": "d8aafa5b8f3e400b60bea0123dd33317" }`
- **403 Forbidden**: The API key does not have read permissions for this operation. Same body
shape as the 401
- **500 Internal Server Error**: Technical error (e.g. database unavailable)

A 400 uses the shared validation envelope, keyed by the offending parameter:

```json
{
  "validationFailures": {
    "$orderby": [
      {
        "PropertyName": "$orderby",
        "ErrorMessage": "Ordering by 'tags' is not supported. Supported fields: reference, numlinks, status, modifiedon, filetype, createdon (Parameter 'propertyName')",
        "AttemptedValue": null
      }
    ]
  }
}
```

Endpoint: GET /files
Version: 2.0.0

## Query parameters:

  - `$filter` (string)
    OData $filter expression — see the supported fields, operators and functions below

  - `$orderby` (string)
    OData $orderby expression — only the fields listed below are supported

  - `$top` (integer)
    Maximum number of records to return (default: 100, max: 100)

  - `$skip` (integer)
    Number of records to skip for pagination (default: 0)

## Header parameters:

  - `X-API-KEY` (string, required)
    Tenant's API key (required)

## Response 200 fields (application/json):

  - `value` (array)
    The files in this page, at most `$top` (default and maximum 100).

  - `value.reference` (string)
    The file's filename, unique per tenant. This is the public key used to address the file and the
value entities use to reference it.

  - `value.numLinks` (integer)
    Number of entities (products, variants, categories, …) currently using this file.

  - `value.status` (string)
    Processing status: `Vd` (void), `Up` (uploading/updating), `Ok` (ready to use),
`Re` (reprocessing), `Er` (processing failed) or `Dv` (deleted). Only `Ok`
guarantees the stored file is usable.

  - `value.modifiedOn` (string)
    When the file was last modified.

  - `value.fileType` (string)
    File extension of the file, without the dot (e.g. `pdf`, `csv`). Derived from the
filename, not from the served Content-Type.

  - `value.createdOn` (string)
    When the file was created. Null for files predating creation-date tracking.

  - `value.tags` (array)
    Tags assigned to the file. Stored as a comma-separated string, so a tag containing a comma is
read back as several tags. Not usable in `$filter` or `$orderby`.

  - `value.url` (string)
    URL of the stored file. Empty until processing has run.

  - `value.sizeInBytes` (integer)
    Size of the file in bytes; `0` until processing has recorded it. Not usable in
`$filter` or `$orderby`.

  - `@count` (integer)
    Total number of files matching the filter, ignoring `$top`/`$skip`.

  - `@readLink` (string)
    Canonical URL of this collection — this request, echoed back. Present only when hypermedia
enrichment is enabled.

  - `@nextLink` (string)
    URL of the next page, omitted on the last page. Present only when hypermedia enrichment is
enabled; otherwise page forward by incrementing `$skip` yourself.

## Response 401 fields (application/json):

  - `message` (string)
    Error description, e.g. `Unauthorized`.

  - `request_id` (string)
    Gateway request identifier, to quote when contacting support.

## Response 403 fields (application/json):

  - `message` (string)

  - `request_id` (string)

## Response 500 fields (application/json):

  - `error` (string)

  - `details` (any)

