# Query language

> One line to search incidents, approvals and the audit log on the server, across years: fields, operators, wildcards, regular expressions, numbers, durations, dates and the time window.

Source: https://docs.3am.si/reference/query-language · Markdown: https://docs.3am.si/reference/query-language.md · All docs: https://docs.3am.si/llms.txt
3AM is an on-prem AI on-call engineer for regulated enterprises (https://3am.si).

The search box on **Incidents**, **Approvals** and the **Audit log** takes plain words or a query, and so does the
API (`query=` on `/v1/episodes`, `/v1/approvals`, `/v1/ledger`). It runs on the server over everything, so a row from
years back is found as easily as today's. It adds to the other filters.

## Cheat sheet

| Write                                                 | Means                                                      |
| ----------------------------------------------------- | ---------------------------------------------------------- |
| `service:core-banking outcome:mitigated`              | Every term must hold (AND)                                 |
| `alert:MySQL* OR alert:HighErrorRate`                 | Either side; AND binds tighter; `*` is a wildcard          |
| `-service:reporting`, `NOT kind:symptom`              | Not                                                        |
| `lock`, `"read only"`                                 | A word or a phrase, anywhere in the row                    |
| `cause="db_read_only"`                                | Exactly                                                    |
| `cause!="db_read_only"`                               | Not exactly                                                |
| `note:timeout`                                        | Contains                                                   |
| `note!:timeout`                                       | Doesn't contain                                            |
| `outcome=none`                                        | Nothing recorded                                           |
| `service:a\|b`                                        | Any of these values                                        |
| `note~"dead ?lock"`                                   | A regular expression, case-insensitive                     |
| `duration>5m`, `related>=2`, `seq<1000`               | Numbers compare; durations take `s`, `m`, `h`, `d`, `w`    |
| `opened>2025-01-01`, `opened<7d`, `opened:2025-01-31` | Times: a date, a timestamp or an age; `:` is "on that day" |
| `since:2025-01-01 until:2025-02-01`, `last:90d`       | The list's time window (`until` is exclusive)              |
| `data.channel:slack`                                  | Audit log: a value inside the event's data, by path        |

The console suggests fields as you type and a field's values after `field:` (Tab takes one), and the `?` in the box
opens the syntax with examples you can click in.

## Fields

| List      | Fields                                                                                                                                                                                  |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Incidents | `id`, `incident`, `service`, `alert`, `cause`, `diagnosis`, `note`, `fix`, `decision`, `outcome`, `result`, `confidence`, `kind`, `autonomy`, `opened`, `closed`, `duration`, `related` |
| Approvals | `id`, `request`, `risk`, `status`, `quorum`, `by`, `decision`, `channel`, `incident`, `action`, `requested`                                                                             |
| Audit log | `seq`, `type`, `actor` (`by`), `reason`, `incident` (`trace`), `time`, `data`                                                                                                           |

`GET /v1/search/fields` lists them. An incident matches when any of its episodes does.

## Rules

* **Dates are UTC** in the API. The console turns dates you type into the instants they mean in your time zone.
* **A query that can't be read is `400 {"error", "code": "bad_query"}`**, naming the fields that exist. Never an empty
  answer.

## Examples

```text
result:handed_over opened<7d                     handed over this week
service:payments-api -kind:symptom duration>10m  long, real failures on one service
type:keychain.* OR type:security.keychain*       every Keychain event (audit log)
actor:console:ana@bank.example type:config.*     what Ana changed
status:pending risk:high                         high-risk approvals waiting
```
