# Workflows

> Step by step: start an alert, add a channel, rename or pause, read saved settings, and run approved paid previews and checks.

Source: https://app.poacher.io/developers/workflows · API version 1.10.1

## What needs the person {#approvals}

| Action | Who | How |
| --- | --- | --- |
| Create and start an alert | The person, in Poacher | `start_alert_in_app` gives them a link |
| Spend from the balance | The agent, after the person agrees to the ceiling | Quote, show the ceiling, then approve |
| Turn on a new channel | The person, who reads the code it received | `confirm_channel` with their code |
| Text-message consent | The person, after reading the disclosure | `sms_consent` on `add_channel` |
| Billing, payment methods, allowance | The person, in Poacher | Not available through the API |

## Start an alert {#start-alert}

1. Find the source with `list_sources`, or use the search page the person is already looking at.
2. Call `start_alert_in_app` with `source_url` and a `brief` in the person’s words.
3. Give the person the link. Poacher opens with the search filled in; they sign in, check the preview and price, and start the alert.

The search travels in the link’s fragment, so nothing is sent to Poacher until the page opens.

## Add a channel {#channels}

Needs `channels:manage`. A new channel stays off until someone enters the 6-digit code sent to it, so a key can never send results somewhere nobody confirmed.

1. `POST /channels` (`add_channel`) with `type` (`slack`, `discord`, `ntfy` or `sms`) and `destination`. Add `alert_id` to put it on that alert once confirmed.
2. Ask the person for the code. It arrives within a minute and works for 10 minutes.
3. `POST /channels/ID/confirm` (`confirm_channel`) with the code. Five wrong codes need `resend_channel_code`.
4. Choose an alert’s channels with `PUT /alerts/ID/channels` (`set_alert_channels`). `[]` keeps results in Poacher only.

```json
{"type":"sms","destination":"+15552014477","alert_id":42,"sms_consent":{"accepted":true,"disclosure_version":"sms-consent-2026-11-12"}}
```

> [!WARNING]
> **Text messages go to US numbers only and cost $0.03 each from the prepaid balance.** Before adding a phone, show the person the disclosure, price, terms and privacy links from `channels.sms` in `get_capabilities`, and send `sms_consent` only after they agree. A number that replies STOP is opted out until it texts START.

Email and browser notifications are set up in the app.

## Rename or pause an alert {#edit}

Needs `alerts:write`. Read the alert first, then send its `edit_revision`.

```bash
curl -X PATCH https://app.poacher.io/api/v1/alerts/42 \
  -H "Authorization: Bearer $POACHER_API_KEY" \
  -H 'If-Match: "EDIT_REVISION"' \
  -H "Idempotency-Key: UNIQUE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Gatsby first editions","status":"paused"}'
```

The response holds the new `edit_revision`. Retrying with the same key and body returns the first response without editing twice. Pausing stops future checks; checks already running finish and are charged. Resuming, filters, schedules and recipients stay in the app.

## Read saved settings {#configuration}

`GET /alerts/ID/configuration` (`get_alert_configuration`, `alerts:read`) returns one consistent snapshot: source URLs and form settings, each source’s interval and schedule, exact filters, the matching brief, selected channels and the accepted minimum. Credentials, recipients and internal set-up details are never included.

Keep `configuration_revision` and send it with a replacement quote: if settings changed since, the quote is refused with `configuration_changed`.

## Run a paid preview {#preview}

Needs `work:execute` and a daily API allowance the person sets in [Developer access](https://app.poacher.io/account/developer). The allowance starts at $0 and covers all keys.

1. `POST /previews` (`quote_preview`) with `url` (or `sources`: 1–10 URLs, each with its own `interval_seconds` and `schedule`), `criteria`, `maximum_charge_micros` and an `Idempotency-Key`. Nothing runs yet.
2. Show the person the ceiling. When they agree, `POST /previews/ID/approve` (`approve_preview`) with the quote’s `request_hash`, using the same key. Quotes expire after 15 minutes.
3. Poll `GET /previews/ID` (`get_preview`) with backoff for status, sample results and the receipt.
4. To stop, `POST /previews/ID/cancel` with `{}`. Work already sent finishes and is charged.

```json
{"url":"https://www.abebooks.com/servlet/SearchResults?kn=great%20gatsby%20first%20edition","criteria":"First edition, first printing, under $5,000","maximum_charge_micros":1000000}
```

> [!NOTE]
> **You are never charged more than the ceiling.** You pay what the work costs plus our margin, so $0.40 of work costs $0.80. Failed attempts cost money too; no work means no charge. A pending `charged_micros` is `null`, never zero.

If any source fails, the preview cannot create or replace an alert, and the cost of the work done is still charged. URLs that import different exact price filters need separate previews. A preview never starts ongoing monitoring. Its `review_url` opens the draft in the app, where the person can start the alert.

## Check an alert now {#check}

Needs `work:execute`. Checks all of an active alert’s sources once, applies its filters and result review, and sends new matches to its channels.

1. `POST /checks` (`quote_check`) with `alert_id`, `maximum_charge_micros` and an `Idempotency-Key`.
2. After the person agrees, `POST /checks/ID/approve` (`approve_check`) with the exact `request_hash`.
3. Read `GET /checks/ID` (`get_check`) for status and the receipt, and `list_results` for the matches.

One check per alert can run at a time. An interrupted or cancelled check is never repeated automatically.
