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

# Ingestion specs — detection

> Every detection rule type, how match modes combine them, and how a spec is selected for an incoming file.

**Detection** decides which spec applies to an incoming file. It's a `match_mode` plus a
list of `rules`.

```json theme={null}
"detection": {
  "match_mode": "composite",
  "rules": [
    { "type": "data_source", "codes": ["pos_polaris"] },
    { "type": "filename_matches", "pattern": "(?i)\\.sav$" }
  ]
}
```

## Match modes

| Mode        | Logic                                                                         |
| ----------- | ----------------------------------------------------------------------------- |
| `any`       | At least one rule matches (OR).                                               |
| `all`       | Every rule matches (AND).                                                     |
| `composite` | Custom combination (typically a data-source gate AND a filename/header test). |

## Rule types

| Type               | Field                 | Meaning                                                                                   |
| ------------------ | --------------------- | ----------------------------------------------------------------------------------------- |
| `data_source`      | `codes` (string\[])   | Restrict the spec to files coming from specific source systems.                           |
| `filename`         | `pattern` (string)    | Exact filename match.                                                                     |
| `filename_matches` | `pattern` (regex)     | Filename matches a regular expression (e.g. `"(?i)tickets"` — `(?i)` = case-insensitive). |
| `columns`          | `columns` (string\[]) | The file's columns must match this list exactly.                                          |
| `header_contains`  | `columns` (string\[]) | The header row must contain **all** of these columns (subset, order-independent).         |
| `sheet_name`       | `pattern` (string)    | An Excel sheet name matches exactly.                                                      |

### `data_source` codes

The `codes` array uses the canonical data-source identifiers, including:

```
pos_polaris, pos_ginkoia, pos_fastmag, pos_kezia, pos_lcv, pos_cegid,
pos_openbravo, pos_oracle, pos_sage, ecommerce_api, erp_sap, user_uploads
```

These are validated when specs are seeded — an unknown code fails fast.

## A composite example

```json theme={null}
"detection": {
  "match_mode": "composite",
  "rules": [
    { "type": "data_source", "codes": ["pos_ginkoia", "user_uploads"] },
    { "type": "filename_matches", "pattern": "(?i)tickets" },
    { "type": "header_contains", "columns": ["Numéro", "Séquence", "Montant", "Mode paiement"] }
  ]
}
```

Reads as: *the file comes from Ginkoia (or a manual upload) **and** its name contains
"tickets" **and** its header has all four columns.*

<Note>
  When several specs could match, the winner is chosen by `priority` then `spec_version`
  — see [Anatomy → priority](/en/developers/ingestion-specs/overview#priority--conflict-resolution).
</Note>
