# Any other source

**In short:** pick the row that matches where your number lives. Each way sends a count, and the first count starts the watch. If your tool can call a link, a webhook URL is the simplest.

Use a recipe when one fits. Otherwise use one of these general methods: every source fits one, and none needs a new endpoint.

| Your source | Method |
|---|---|
| A count you can query: a SQL database (Postgres, MySQL, MariaDB), a warehouse or log store (ClickHouse, Tinybird), another service's API | **Scheduled query → ingest.** A cron job or a CI schedule runs every 60 minutes (Free) or every 5 minutes (Pro). It counts per 5-minute bucket over the last 2 hours, **every bucket, zeros included** (`generate_series` in SQL, `WITH FILL` in ClickHouse), up to the last complete bucket, and sends them with `set` to an **explicit** watch: a re-send replaces a bucket (never doubles it), late rows are picked up, and a stopped job raises the no-data alert. Written out and run in CI: [Watch a ClickHouse query](https://staging.countwatch.com/docs/methods/clickhouse.md). |
| Your own code sees each event (an app, a worker, a job) | **Client library:** `npm install countwatch` or `pip install countwatch`, then `cw.count("orders")`. It sums per 5 minutes, sends a 0 for each empty 5-minute bucket of every metric it has seen (an explicit watch: a stopped process raises the no-data alert), sends at the account's interval (`send_interval_seconds` in `GET /v1/status`, read again after each send) and retries without double counts. Declare metrics at start (`metrics`) to get zeros before their first event. Serverless (no timer): call `flush()` before returning; the watch is then a push watch. |
| A tool that sends webhooks or can call a URL (forms, no-code tools, CI) | **Webhook URL:** made in the dashboard (https://staging.countwatch.com/dashboard) and pasted into the tool; each hit adds 1 (or `?n=`); a delivery id (`?id=` or the sender's delivery header) counts a retry once. It makes a **push** watch: the link is called as things happen, so a bucket with no hits is zero. |
| A shell script or cron job that finishes something often (every few minutes or more) | **`npx countwatch send <metric> [n] --dim key=value`** at the end of the script (a push watch). A push watch never raises a no-data alert, so for a job that runs rarely, count with a scheduled query instead. |
| Past data: the scheduled query over the last 89 days, or an export file (CSV) | **Import once:** count per 5 minutes, every bucket (an empty one is a `0`), with UTC bucket starts, and send it with `POST /v1/import` (`resolution: "5m"`; the API takes up to 90 days back, and the examples take 89 days so the first bucket is still inside the 90 days when the request arrives), ending where the scheduled sends begin. The API stops an import at a watch's first live bucket, so it never overwrites live counts. `"1h"` or `"1d"` only for a source that keeps nothing finer (they are spread evenly over 5-minute buckets). |

Rules for any method:

- Create the watch first, with its final source (it cannot change): an explicit watch by its first `set` points, a push watch by one point `{"metric": "…", "add": 0}` with `"source": "push"`.
- One metric per thing counted (`orders`, `signups`); dimensions only for a few values each (every combination is a watch, within the plan's watch limit).
- Batch scheduled sends: one request carries up to 10,000 points.
- Keys and webhook URLs are secrets, made in the dashboard (https://staging.countwatch.com/dashboard) and pasted into the host's secrets: a write key (`COUNTWATCH_API_KEY`) goes into senders, a webhook URL (`COUNTWATCH_PING_URL`) into tools that call a URL. Code reads those names; an agent never handles the values.
- Then the same checks as every recipe: `GET /v1/status` (an explicit watch's `missing_buckets_24h` stays 0), the import's `status: done`, a test alert.

The scheduled query's request (`ts` is each bucket's start, ISO 8601 or Unix milliseconds, at most 6 hours back):

```
curl -sX POST https://staging.countwatch.com/v1/ingest -H "Authorization: Bearer $COUNTWATCH_API_KEY" -H "Content-Type: application/json" \
  -d '{"points":[{"metric":"orders","ts":"<bucket start>","set":7},{"metric":"orders","ts":"<next bucket start>","set":0}]}'
```
