# Signals

A signal is a question SigWise answers about every object. You define it with
`PUT /v1/signals/{key}`; the same call updates it later.

```json
{
  "type": "noul",
  "instructions": "Decide if this user is likely a scammer.",
  "criteria": { "true": "clear scam signals", "false": "legitimate behaviour" },
  "enabled": true
}
```

- `key` (in the path) is the stable name you read answers by. Use letters,
  digits and underscores, such as `is_scammer`.
- `instructions` tell the analyzer what to decide. Usually a sentence; objects
  and arrays are passed through verbatim for structured prompts.
- `criteria` describe the possible answers. Their shape depends on `type`.
- `enabled` (default `true`) switches the signal off without deleting it or its
  answers.

## Types

### `noul`: yes or no

The answer is `noul`, the probability (0 to 1) that the answer is **yes**.

```json
{
  "type": "noul",
  "instructions": "Will this user churn in the next 30 days?",
  "criteria": { "true": "disengaging, complaining, cancelling", "false": "active and satisfied" }
}
```

```json
{ "key": "churn_risk", "type": "noul", "noul": 0.27 }
```

`criteria` is an object with optional `true` and `false` descriptions.

### `score`: a labelled spectrum

The answer is `score`, a position on an ordered list of levels: `0` is the
first level and `levels − 1` the last, with fractions in between. It also
carries `probabilities` and a `confidence`.

```json
{
  "type": "score",
  "instructions": "Rate overall trustworthiness.",
  "criteria": ["high risk", "neutral", "trusted"]
}
```

```json
{ "key": "trust_score", "type": "score", "score": 1.63, "confidence": 0.8 }
```

`criteria` is an array of level descriptions, from lowest to highest.

### `choice`: one of N

The answer is `choice`, the most likely option, with `probabilities` for
every option and a `confidence`.

```json
{
  "type": "choice",
  "instructions": "Classify the buyer's intent.",
  "criteria": { "browsing": null, "comparing": "asks about alternatives", "ready_to_buy": "asks how to pay" }
}
```

```json
{
  "key": "buyer_intent",
  "type": "choice",
  "choice": "ready_to_buy",
  "probabilities": { "browsing": 0.05, "comparing": 0.15, "ready_to_buy": 0.8 },
  "confidence": 0.8
}
```

`criteria` maps each option to a description, or to `null` when the name says it all.

## Default signals

Every new account starts with three signals, so the first events already get
answers: `is_scammer` (noul), `trust_score` (score) and `buyer_intent`
(choice). Change or delete them like any other signal.

## Writing good signals

- **Ask one thing.** "Is this a scammer?" works better than "Is this a scammer
  or a spammer?" Make two signals instead.
- **Describe the evidence.** Criteria like "asks to pay outside the platform"
  steer the analyzer more than "suspicious".
- **Pick the type by what you will do with it.** Thresholds and alerts suit
  `noul`; ranking suits `score`; routing suits `choice`.
- **Name keys for conditions.** Keys appear in [search and rule
  conditions](https://sigwise.ai/docs/guides/queries.md), such as `is_scammer >= 90`.

## Changing signals

- A new or changed signal is used from the **next** analysis of each object.
  Objects not analyzed since show it in `pending`.
- To answer a new signal for existing objects, run a [backfill](https://sigwise.ai/docs/guides/backfills.md),
  or turn on `auto_backfill_signals` in [settings](https://sigwise.ai/docs/reference.md#tag/account) to
  backfill every new signal automatically.
- Deleting a signal removes it from future analyses.

## Endpoints

| | |
|---|---|
| GET `/v1/signals` | List signals |
| PUT `/v1/signals/{key}` | Create or update a signal |
| DELETE `/v1/signals/{key}` | Delete a signal |
| GET `/v1/signals/{key}/backfill` | Backfill estimate and progress |
| POST `/v1/signals/{key}/backfill` | Start a backfill |
