URL: /code/data/monitors/check · Id: `page:/code/data/monitors/check`

# Monitor.check

> Run a Monitor once, now, and record what it saw as an Event, at the price of the call it wraps.

`POST https://api.sb/{your-domain}/monitors/check`

Run a [Monitor](https://startupbuilder.dev/business/nouns/monitor) once, now, and record what it saw as an [Event](https://startupbuilder.dev/business/nouns/event), at the price of the call it wraps.

- **Price:** Free
- **Success rate:** 99.6% of 2,079,088 calls
- **Freshness:** Read fresh each call
- **Emits:** `Monitor.checked`
- **Capability:** [Schedules](https://startupbuilder.dev/code/platform/schedules)

```text title="Run it · Ask"
Check the rank Monitor on “rent tracking app for landlords” now.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Monitor.check({ monitor: 'monitor_Rk2a', maxCost: 0.01 })
```

```json title="Run it · Response"
{
  "monitor": "monitor_Rk2a",
  "ranAt": "2026-10-27T14:28:00Z",
  "changed": true,
  "summary": "leaseline.app entered the results for “rent tracking app for landlords” at position 18.",
  "event": "https://api.sb/leaseline.app/events/evt_5bQ1",
  "cost": {
    "usd": 0,
    "maxUsd": 0.0003,
    "units": 1,
    "misses": 0
  }
}
```

## Inputs
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `monitor` | `Monitor` | Required | The Monitor to run. Also served at `/monitors/{monitor}/check`, as the hub defines it. |

## Outputs
| Field | Type | What `null` means |
| --- | --- | --- |
| `monitor` | `Monitor` | Never null: with its latest result. |
| `ranAt` | `string`, in ISO 8601 | Never null. |
| `changed` | `boolean` | Never null: whether this run crossed the Monitor’s `change` and `threshold`. |
| `summary` | `string` | Never null: what moved, in one sentence. |
| `event` | `string` | Never null: the address of the Event this run recorded. |
| `cost` | [`Cost`](/code/data/types#cost), in USD | Never null: what the wrapped call spent. |

## Read the result
| Field | Value | What it means | What to do |
| --- | --- | --- | --- |
| `changed` | `false` | The run saw nothing past the threshold. It still recorded the reading, so the curve has the point. | Nothing; read the trend with `Metric.query`, not run by run. (the contract every data call keeps) |
| `changed` | `true` once, then `false` | A one-run move is usually noise in ranks and AI answers. | Act on a change that holds for 2 runs in a row, or 2 weeks for answers. (our planning number) |

## Effects
**Action class**

None: no approval rule names it, so it runs within its seat’s Permissions and Limits

**Modes**

- `try`: Runs the wrapped call and returns what it saw; nothing is recorded and nothing is billed.
- `send`: Returns a pending Action at once; its Event carries the rows when the read finishes.
- `do`: Waits for the read and returns the rows, billed per result.

**Idempotency**

The same `Idempotency-Key` with the same input replays the first answer at $0; with other input it returns 409.

**Saved or shared**

Records the run as an Event on the Monitor, with the wrapped call’s own Event beside it.

**Emits**

`Monitor.checked` with `{ monitor, changed, summary, event }`

**Performed by**

[Analyst](https://startupbuilder.dev/agents/marketing/analyst)

**Price**

Free. Free: the check itself; the wrapped call bills at its own price.

**Reliability**

The first route succeeds 99.6% of 2,079,088 calls. If it fails, the call refuses with `sources-busy` and nothing is spent.

**Freshness**

Every call reads fresh. Readings about people are never shared across startups.

**Batch and pages**

Up to 1 Monitor a call. It answers in one response.

**Rate**

[The shared rate rules](/code/data#rate): 10 calls a second per key, and an array input counts as one call.

## Refuses when
This call has no refusals of its own. Every data call can also meet [the shared data-call refusals](/code/refusals#data-calls): [`filter-unsupported`](/code/refusals#filter-unsupported), [`input-missing`](/code/refusals#input-missing), [`limit-exceeded`](/code/refusals#limit-exceeded), [`max-cost`](/code/refusals#max-cost), [`rate-limited`](/code/refusals#rate-limited), [`sources-busy`](/code/refusals#sources-busy), [`venue-unsupported`](/code/refusals#venue-unsupported).

## When it waits
Returns in one response; nothing waits.

## Example

**Ask**

```text
Check the rank Monitor on “rent tracking app for landlords” now.
```

**API**

```bash
curl -X POST "https://api.sb/leaseline.app/monitors/check?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"monitor":"monitor_Rk2a","maxCost":0.01}'
```

The response is the one in the Run it window above.

**CLI**

```bash
npx startup-builder do Monitor.check --try --data '{"monitor":"monitor_Rk2a","maxCost":0.01}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Monitor.check({ monitor: 'monitor_Rk2a', maxCost: 0.01 })"
  }
}
```

**SDK**

```ts
import { $ } from 'startup-builder'

const result = await $.try.Monitor.check({
  monitor: 'monitor_Rk2a',
  maxCost: 0.01,
})
```

To retry, send the same `Idempotency-Key`: the retry returns the first answer for $0. A new key reads again.

A `sk_test_` key answers these the same way every time, at $0 ([every test value](/code/data#test-values)).

| Test value | Always returns | What it is for |
| --- | --- | --- |
| `maxCost: 0.0001` | Refuses with [`max-cost`](/code/refusals#max-cost) | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
| `rate-limited.test` | Refuses with [`rate-limited`](/code/refusals#rate-limited) | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
| `sources-busy.test` | Refuses with [`sources-busy`](/code/refusals#sources-busy) | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |

## Used by
None.

## Related
[`Monitor.create`](/code/data/monitors/create)